Compare commits

..

No commits in common. "main" and "1.0.7" have entirely different histories.
main ... 1.0.7

153 changed files with 31411 additions and 18317 deletions

View File

@ -13,10 +13,6 @@ The android application is available here:
<br> <br>
[Lantern Power Monitor - Google Play](https://play.google.com/store/apps/details?id=com.lanternsoftware.lantern) [Lantern Power Monitor - Google Play](https://play.google.com/store/apps/details?id=com.lanternsoftware.lantern)
<br><br> <br><br>
The iOS application is available here:
<br>
[Lantern Power Monitor - App Store](https://apps.apple.com/us/app/lantern-power-monitor/id1620735464)
<br><br>
The LanternPowerMonitor subreddit is a great place to ask questions and stay tuned for updates and news. The LanternPowerMonitor subreddit is a great place to ask questions and stay tuned for updates and news.
<br> <br>
[/r/LanternPowerMonitor](https://www.reddit.com/r/LanternPowerMonitor/) [/r/LanternPowerMonitor](https://www.reddit.com/r/LanternPowerMonitor/)
@ -49,15 +45,15 @@ This is only tangentially related. A java library for running a zwave controlle
# Ok, how do I run this thing? # Ok, how do I run this thing?
The easiest way to run the software on a hub is to download a pre-built SD card image. One can be downloaded here:<br> The easiest way to run the software on a hub is to download a pre-built SD card image. One can be downloaded here:<br>
[hub_1.1.1.zip](https://cf.lanternpowermonitor.com/hub_1.1.1.zip) [hub_1.0.7.zip](https://cf.lanternpowermonitor.com/hub_1.0.7.zip)
<br><br> <br><br>
Flash this to any micro sd card (4gig or larger) and you're good to go. Fire up the hub and the phone app should be able to connect to it via bluetooth to finish the configuration. The default password on this image is pi/LanternPowerMonitor<br><br> Flash this to any micro sd card (4gig or larger) and you're good to go. Fire up the hub and the phone app should be able to connect to it via bluetooth to finish the configuration. The default password on this image is pi/LanternPowerMonitor<br><br>
When you add the hub to your configuration via the app, you can change where the hub posts data. If you use lanternpowermonitor.com (the default host), your data will be stored there securely and won't be shared with or sold to anyone. If you really want to run your own server, you're of course welcome to do that instead, instructions are located further down. When you add the hub to your configuration via the app, you can change where the hub posts data. If you use lanternsoftware.com (the default host), your data will be stored there securely and won't be shared with or sold to anyone. If you really want to run your own server, you're of course welcome to do that instead, instructions are located further down.
## Now that the service is running on the pi, how do I configure everything in the android app? ## Now that the service is running on the pi, how do I configure everything in the android app?
1. Create your panel in the "Configure Panels" page from the main menu. Before you have your hub connected, there will be no place to select a hub and port for each breaker. Don't worry, we'll get to that later. 1. Create your panel in the "Configure Panels" page from the main menu. Before you have your hub connected, there will be no place to select a hub and port for each breaker. Don't worry, we'll get to that later.
1. With your hub plugged in and running for at least a minute, go into the "Configure Hubs" page from the main menu. In here you'll see a status of "Scanning for Hubs..." If you're in range of your hub and its service is running, the app should find it pretty quickly (less than 15 seconds). If this is the first hub you've added, it will prompt you for your wifi credentials. After that, it will send via bluetooth the hub index (so it knows which hub it is), host (so it knows where to post data), auth code (so it knows which account it is and can post data), the encrypted wifi credentials, and finally a command to reboot. 1. With your hub plugged in and running for at least 30 seconds or so, go into the "Configure Hubs" page from the main menu. In here you'll see a status of "Scanning for Hubs..." (if you're on at least 1.0.7 of the app). If you're in range of your hub and its service is running, the app should find it pretty quickly (less than 15 seconds). If this is the first hub you've added, it will prompt you for your wifi credentials. After that, it will send via bluetooth the hub index (so it knows which hub it is), host (so it knows where to post data), auth code (so it knows which account it is and can post data), the encrypted wifi credentials, and finally a command to reboot.
1. After your hub reboots, it should acquire an ip from your router, start the service, and try to start posting data. The hubs will try to auto-calibrate your voltage to 120V too, but if your AC/AC transformer is not plugged in, it will notice that and not try to auto-calibrate. It will continue to try to auto-calibrate each time you restart the hub until it does so succesfully. 1. After your hub reboots, it should acquire an ip from your router, start the service, and try to start posting data. The hubs will try to auto-calibrate your voltage to 120V too, but if your AC/AC transformer is not plugged in, it will notice that and not try to auto-calibrate. It will continue to try to auto-calibrate each time you restart the hub until it does so succesfully.
@ -76,17 +72,27 @@ First, you and I will get along just fine. Second, do a reactor build from the
The compiled service will be at LanternPowerMonitor/currentmonitor/lantern-currentmonitor/target/lantern-currentmonitor.jar<br> The compiled service will be at LanternPowerMonitor/currentmonitor/lantern-currentmonitor/target/lantern-currentmonitor.jar<br>
This is a shaded jar that contains all of the required components to function. It must be copied to /opt/currentmonitor on the pi.<br><br> This is a shaded jar that contains all of the required components to function. It must be copied to /opt/currentmonitor on the pi.<br><br>
After that, you need to install pigpio: After that, you need to install wiring-pi:
``` ```
sudo apt-get install pigpio sudo apt-get install wiringpi
``` ```
You also need to have java 1.8 or newer installed. You also need to have java 1.8 or newer installed.
Create a configuration file at /opt/currentmonitor/config.json<br>
Use the format below to get started
```
{
"hub": 0,
"host": "https://lanternsoftware.com/currentmonitor",
"auto_calibration_voltage": 120.0,
"needs_calibration": true
}
```
To install the current monitor service, use a service file like the one below: To install the current monitor service, use a service file like the one below:
``` ```
[Unit] [Unit]
Description=Current Monitor Description=Current Monitor
After=syslog.target network-online.target After=syslog.target network.target
Wants=network-online.target
[Service] [Service]
Type=simple Type=simple
@ -113,7 +119,7 @@ After your reactor build, the compiled war will be at LanternPowerMonitor/curren
That can be deployed to tomcat. The 'host' parameter in the raspberry pi config.json file needs to point to wherever you deploy the service so your hubs post the data to your server instead of the official lantern software one.<br> That can be deployed to tomcat. The 'host' parameter in the raspberry pi config.json file needs to point to wherever you deploy the service so your hubs post the data to your server instead of the official lantern software one.<br>
I'd recommend a valid dns entry and an ssl certificate, but, it's up to you, you're already knee deep in "I'll do what I want" territory here.<br><br> I'd recommend a valid dns entry and an ssl certificate, but, it's up to you, you're already knee deep in "I'll do what I want" territory here.<br><br>
Before you deploy it, you need to generate a config file that contains the mongodb credentials.<br> Before you deploy it, you need to generate a config file that contains the mongodb credentials.<br>
There is a file at lantern-config-currentmonitor/src/main/java/com/lanternsoftware/currentmonitor/CreateMongoConfig.java that can do this for you.<br> There is a file at lantern-service-currentmonitor/src/test/java/com/lanternsoftware/currentmonitor/CreateMongoConfig.java that can do this for you.<br>
Place the generated config file in /opt/tomcat (which is where I have tomcat installed). If you want it to be read from somewhere else, you can modify the paths in LanternFiles.java<br><br> Place the generated config file in /opt/tomcat (which is where I have tomcat installed). If you want it to be read from somewhere else, you can modify the paths in LanternFiles.java<br><br>
The last thing you need is a private aes key to encrypt user auth tokens. One of those can be generated with CreateAuthKey.java.<br> The last thing you need is a private aes key to encrypt user auth tokens. One of those can be generated with CreateAuthKey.java.<br>
I realize these instructions aren't complete, but if you're going down this path, I suspect you sort of already know what you're doing, so hopefully that's enough to point you in the right direction. I realize these instructions aren't complete, but if you're going down this path, I suspect you sort of already know what you're doing, so hopefully that's enough to point you in the right direction.

Binary file not shown.

View File

@ -1,10 +0,0 @@
LCSC Part Number,Quantity
C2977589,1
C43846,1
C43840,1
C385441,2
C385449,1
C385460,1
C385498,1
C433508,1
C397337,16
1 LCSC Part Number Quantity
2 C2977589 1
3 C43846 1
4 C43840 1
5 C385441 2
6 C385449 1
7 C385460 1
8 C385498 1
9 C433508 1
10 C397337 16

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,105 +0,0 @@
<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>
<artifactId>lantern-config-currentmonitor</artifactId>
<packaging>jar</packaging>
<version>1.1.0</version>
<name>lantern-config-currentmonitor</name>
<parent>
<groupId>com.lanternsoftware.currentmonitor</groupId>
<artifactId>currentmonitor</artifactId>
<version>1.1.0</version>
</parent>
<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.lanternsoftware.util</groupId>
<artifactId>lantern-util-dao-mongo</artifactId>
<version>${util.version}</version>
</dependency>
<dependency>
<groupId>com.lanternsoftware.util</groupId>
<artifactId>lantern-util-common</artifactId>
<version>${util.version}</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.10.1</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>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<finalName>lantern-config-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.CreateMongoConfig</Main-Class>
<Specification-Title>Lantern Power Monitor</Specification-Title>
<Specification-Version>${project.version}</Specification-Version>
<Specification-Vendor>Lantern Software, Inc.</Specification-Vendor>
</manifestEntries>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -1,14 +0,0 @@
package com.lanternsoftware.currentmonitor;
import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.dao.mongo.MongoConfig;
import com.lanternsoftware.util.external.LanternFiles;
public class CreateMongoConfig {
public static void main(String[] args) {
if (CollectionUtils.size(args) == 3)
new MongoConfig(args[0], args[1], args[2], "CURRENT_MONITOR").saveToDisk(LanternFiles.CONFIG_PATH + "mongo.cfg");
else
new MongoConfig("lanternsoftware.com", "*redacted*", "*redacted*", "CURRENT_MONITOR").saveToDisk(LanternFiles.CONFIG_PATH + "mongo.cfg");
}
}

View File

@ -1,15 +1,15 @@
<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"> <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> <modelVersion>4.0.0</modelVersion>
<groupId>com.lanternsoftware.currentmonitor</groupId>
<artifactId>lantern-currentmonitor</artifactId> <artifactId>lantern-currentmonitor</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<version>1.1.3</version> <version>1.0.7</version>
<name>lantern-currentmonitor</name> <name>lantern-currentmonitor</name>
<parent> <properties>
<groupId>com.lanternsoftware.currentmonitor</groupId> <maven.compiler.source>1.8</maven.compiler.source>
<artifactId>currentmonitor</artifactId> <maven.compiler.target>1.8</maven.compiler.target>
<version>1.1.0</version> </properties>
</parent>
<dependencies> <dependencies>
<dependency> <dependency>
@ -23,9 +23,9 @@
<version>1.2.3</version> <version>1.2.3</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.lanternsoftware.pigpio</groupId> <groupId>com.pi4j</groupId>
<artifactId>lantern-pigpio</artifactId> <artifactId>pi4j-gpio-extension</artifactId>
<version>${pigpio.version}</version> <version>1.3</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.github.hypfvieh</groupId> <groupId>com.github.hypfvieh</groupId>
@ -35,12 +35,12 @@
<dependency> <dependency>
<groupId>com.lanternsoftware.currentmonitor</groupId> <groupId>com.lanternsoftware.currentmonitor</groupId>
<artifactId>lantern-datamodel-currentmonitor</artifactId> <artifactId>lantern-datamodel-currentmonitor</artifactId>
<version>${cm.version}</version> <version>1.0.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.lanternsoftware.util</groupId> <groupId>com.lanternsoftware.util</groupId>
<artifactId>lantern-util-http</artifactId> <artifactId>lantern-util-http</artifactId>
<version>${util.version}</version> <version>1.0.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.eclipse.paho</groupId> <groupId>org.eclipse.paho</groupId>
@ -58,7 +58,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version> <version>3.2</version>
<executions> <executions>
<execution> <execution>
<goals> <goals>
@ -71,14 +71,14 @@
<optimize>true</optimize> <optimize>true</optimize>
<showDeprecation>true</showDeprecation> <showDeprecation>true</showDeprecation>
<encoding>UTF-8</encoding> <encoding>UTF-8</encoding>
<source>${maven.compiler.source}</source> <source>1.8</source>
<target>${maven.compiler.target}</target> <target>1.8</target>
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId> <artifactId>maven-shade-plugin</artifactId>
<version>3.3.0</version> <version>3.2.1</version>
<configuration> <configuration>
<createDependencyReducedPom>false</createDependencyReducedPom> <createDependencyReducedPom>false</createDependencyReducedPom>
<filters> <filters>

View File

@ -7,38 +7,27 @@ import com.lanternsoftware.currentmonitor.bluetooth.BleHelper;
import com.lanternsoftware.currentmonitor.bluetooth.BleService; import com.lanternsoftware.currentmonitor.bluetooth.BleService;
import com.lanternsoftware.datamodel.currentmonitor.HubConfigService; import com.lanternsoftware.datamodel.currentmonitor.HubConfigService;
import com.lanternsoftware.util.CollectionUtils; import com.lanternsoftware.util.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List; import java.util.List;
public class BluetoothConfig { public class BluetoothConfig {
private static final Logger LOG = LoggerFactory.getLogger(BluetoothConfig.class);
private final BleApplication app; private final BleApplication app;
public BluetoothConfig(String _hubName, BleCharacteristicListener _listener) { public BluetoothConfig(String _hubName, BleCharacteristicListener _listener) {
BleApplication a = null; BleHelper.getAdapter().setPowered(true);
try { BleHelper.requestBusName("com.lanternsoftware");
BleHelper.getAdapter().setPowered(true); BleHelper.setBasePath("/com/lanternsoftware");
BleHelper.requestBusName("com.lanternsoftware"); HubConfigService service = new HubConfigService();
BleHelper.setBasePath("/com/lanternsoftware"); List<BleCharacteristic> chars = CollectionUtils.transform(service.getCharacteristics(), _c->new BleCharacteristic("HubConfig", _c.getUUID(), _c.name(), _c.getFlags()));
List<BleCharacteristic> chars = CollectionUtils.transform(HubConfigService.getCharacteristics(), _c -> new BleCharacteristic("HubConfig", _c.getUUID(), _c.name(), _c.getFlags())); chars.forEach(_c->_c.setListener(_listener));
chars.forEach(_c -> _c.setListener(_listener)); app = new BleApplication("Lantern", _hubName, new BleService("HubConfig", service.getServiceUUID(), chars));
a = new BleApplication("Lantern", _hubName, new BleService("HubConfig", HubConfigService.getServiceUUID(), chars));
}
catch (Throwable _t) {
LOG.error("Failed to initialize BLE service", _t);
}
app = a;
} }
public void start() { public void start() {
if (app != null) app.start();
app.start();
} }
public void stop() { public void stop() {
if (app != null) app.stop();
app.stop();
} }
} }

View File

@ -1,20 +1,18 @@
package com.lanternsoftware.currentmonitor; package com.lanternsoftware.currentmonitor;
import com.lanternsoftware.currentmonitor.adc.MCP3008Pin;
import com.lanternsoftware.datamodel.currentmonitor.Breaker; import com.lanternsoftware.datamodel.currentmonitor.Breaker;
import com.lanternsoftware.datamodel.currentmonitor.hub.PowerSample; import com.pi4j.io.gpio.GpioPinAnalogInput;
import java.util.List; import java.util.List;
public class BreakerSamples { public class BreakerSamples {
private final Breaker breaker; private final Breaker breaker;
private final MCP3008Pin voltagePin; private final GpioPinAnalogInput voltagePin;
private final MCP3008Pin currentPin; private final GpioPinAnalogInput currentPin;
private final List<PowerSample> samples; private final List<PowerSample> samples;
private int cycleCnt;
private int sampleCnt; private int sampleCnt;
public BreakerSamples(Breaker _breaker, MCP3008Pin _voltagePin, MCP3008Pin _currentPin, List<PowerSample> _samples) { public BreakerSamples(Breaker _breaker, GpioPinAnalogInput _voltagePin, GpioPinAnalogInput _currentPin, List<PowerSample> _samples) {
breaker = _breaker; breaker = _breaker;
voltagePin = _voltagePin; voltagePin = _voltagePin;
currentPin = _currentPin; currentPin = _currentPin;
@ -25,11 +23,11 @@ public class BreakerSamples {
return breaker; return breaker;
} }
public MCP3008Pin getVoltagePin() { public GpioPinAnalogInput getVoltagePin() {
return voltagePin; return voltagePin;
} }
public MCP3008Pin getCurrentPin() { public GpioPinAnalogInput getCurrentPin() {
return currentPin; return currentPin;
} }
@ -37,20 +35,8 @@ public class BreakerSamples {
return samples; return samples;
} }
public void incrementCycleCnt() { public PowerSample getSample(int _sample) {
cycleCnt++; return samples.get(_sample);
}
public PowerSample incrementSample() {
return samples.get(sampleCnt++);
}
public int getCycleCnt() {
return cycleCnt;
}
public void setCycleCnt(int _cycleCnt) {
cycleCnt = _cycleCnt;
} }
public int getSampleCnt() { public int getSampleCnt() {

View File

@ -1,55 +1,51 @@
package com.lanternsoftware.currentmonitor; package com.lanternsoftware.currentmonitor;
import com.lanternsoftware.currentmonitor.adc.MCP3008;
import com.lanternsoftware.currentmonitor.adc.MCP3008Pin;
import com.lanternsoftware.datamodel.currentmonitor.Breaker; import com.lanternsoftware.datamodel.currentmonitor.Breaker;
import com.lanternsoftware.datamodel.currentmonitor.BreakerHub; import com.lanternsoftware.datamodel.currentmonitor.BreakerHub;
import com.lanternsoftware.datamodel.currentmonitor.BreakerPolarity; import com.lanternsoftware.datamodel.currentmonitor.BreakerPolarity;
import com.lanternsoftware.datamodel.currentmonitor.BreakerPower; import com.lanternsoftware.datamodel.currentmonitor.BreakerPower;
import com.lanternsoftware.datamodel.currentmonitor.hub.BreakerSample;
import com.lanternsoftware.datamodel.currentmonitor.hub.HubSample;
import com.lanternsoftware.datamodel.currentmonitor.hub.PowerSample;
import com.lanternsoftware.pigpio.PiGpioFactory;
import com.lanternsoftware.util.CollectionUtils; import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.concurrency.ConcurrencyUtils; 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.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
public class CurrentMonitor { public class CurrentMonitor {
private static final Logger LOG = LoggerFactory.getLogger(CurrentMonitor.class); private static final Logger LOG = LoggerFactory.getLogger(CurrentMonitor.class);
private static final int BATCH_CNT = 4; private static final int BATCH_CNT = 4;
private GpioController gpio;
private final ExecutorService executor = Executors.newCachedThreadPool(); private final ExecutorService executor = Executors.newCachedThreadPool();
private final Map<Integer, MCP3008> chips = new HashMap<>(); private final Map<Integer, AdcGpioProvider> chips = new HashMap<>();
private final Map<Integer, GpioPinAnalogInput> pins = new HashMap<>();
private Sampler sampler; private Sampler sampler;
private PowerListener listener; private PowerListener listener;
private boolean debug = false; private boolean debug = false;
private boolean postSamples = false;
public boolean isDebug() { public void start() {
return debug; try {
} gpio = GpioFactory.getInstance();
LOG.info("Current Monitor Started");
public void setDebug(boolean _debug) { }
debug = _debug; catch (Throwable t) {
} LOG.info("Failed to get gpio factory", t);
}
public boolean isPostSamples() {
return postSamples;
}
public void setPostSamples(boolean _postSamples) {
postSamples = _postSamples;
} }
public void stop() { public void stop() {
@ -57,15 +53,21 @@ public class CurrentMonitor {
ConcurrencyUtils.sleep(1000); ConcurrencyUtils.sleep(1000);
executor.shutdown(); executor.shutdown();
ConcurrencyUtils.sleep(1000); ConcurrencyUtils.sleep(1000);
PiGpioFactory.shutdown();
chips.clear(); chips.clear();
pins.clear();
gpio.shutdown();
LOG.info("Power Monitor Service Stopped"); LOG.info("Power Monitor Service Stopped");
} }
public void setDebug(boolean _debug) {
debug = _debug;
}
public CalibrationResult calibrateVoltage(double _curCalibration) { public CalibrationResult calibrateVoltage(double _curCalibration) {
LOG.info("Calibrating Voltage"); GpioPinAnalogInput voltagePin = getPin(0, 0);
MCP3008Pin voltagePin = new MCP3008Pin(getChip(0), 0); if (voltagePin == null)
int maxSamples = 240000; return null;
int maxSamples = 120000;
CalibrationSample[] samples = new CalibrationSample[maxSamples]; CalibrationSample[] samples = new CalibrationSample[maxSamples];
int offset = 0; int offset = 0;
for (;offset < maxSamples; offset++) { for (;offset < maxSamples; offset++) {
@ -75,7 +77,7 @@ public class CurrentMonitor {
long intervalEnd = System.nanoTime() + 2000000000L; //Scan voltage for 2 seconds long intervalEnd = System.nanoTime() + 2000000000L; //Scan voltage for 2 seconds
while (offset < maxSamples) { while (offset < maxSamples) {
samples[offset].time = System.nanoTime(); samples[offset].time = System.nanoTime();
samples[offset].voltage = voltagePin.read(); samples[offset].voltage = voltagePin.getValue();
offset++; offset++;
if (samples[offset-1].time > intervalEnd) if (samples[offset-1].time > intervalEnd)
break; break;
@ -126,12 +128,10 @@ public class CurrentMonitor {
stopMonitoring(); stopMonitoring();
listener = _listener; listener = _listener;
List<Breaker> validBreakers = CollectionUtils.filter(_breakers, _b -> _b.getPort() > 0 && _b.getPort() < 16); List<Breaker> validBreakers = CollectionUtils.filter(_breakers, _b -> _b.getPort() > 0 && _b.getPort() < 16);
if (CollectionUtils.isEmpty(validBreakers)) { if (CollectionUtils.isEmpty(validBreakers))
LOG.error("No breakers found for hub number {}", _hub.getHub());
return; return;
}
LOG.info("Monitoring {} breakers for hub {}", CollectionUtils.size(validBreakers), _hub.getHub()); LOG.info("Monitoring {} breakers for hub {}", CollectionUtils.size(validBreakers), _hub.getHub());
sampler = new Sampler(_hub, validBreakers, _intervalMs, 5); sampler = new Sampler(_hub, validBreakers, _intervalMs, 2);
LOG.info("Starting to monitor ports {}", CollectionUtils.transformToCommaSeparated(validBreakers, _b -> String.valueOf(_b.getPort()))); LOG.info("Starting to monitor ports {}", CollectionUtils.transformToCommaSeparated(validBreakers, _b -> String.valueOf(_b.getPort())));
executor.submit(sampler); executor.submit(sampler);
} }
@ -140,15 +140,34 @@ public class CurrentMonitor {
} }
} }
private synchronized MCP3008 getChip(int _chip) { private GpioPinAnalogInput getPin(int _chip, int _pin) {
MCP3008 chip = chips.get(_chip); GpioPinAnalogInput pin;
if (chip == null) { synchronized (pins) {
String id = "SPI" + _chip; AdcGpioProvider chip = chips.get(_chip);
LOG.info("Creating chip {}", id); if (chip == null) {
chip = new MCP3008(PiGpioFactory.getSpiChannel(_chip, 810000, false)); SpiChannel channel = SpiChannel.getByNumber(_chip);
chips.put(_chip, 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 chip; return pin;
}
private Integer pinKey(int _chip, int _pin) {
return (_chip*8)+_pin;
} }
public void submit(Runnable _runnable) { public void submit(Runnable _runnable) {
@ -166,19 +185,19 @@ public class CurrentMonitor {
private boolean running = true; private boolean running = true;
private final BreakerHub hub; private final BreakerHub hub;
private final List<List<BreakerSamples>> breakers; private final List<List<BreakerSamples>> breakers;
private final long intervalNs; private final int intervalNs;
private final int concurrentBreakerCnt; private final int concurrentBreakerCnt;
public Sampler(BreakerHub _hub, List<Breaker> _breakers, long _intervalMs, int _concurrentBreakerCnt) { public Sampler(BreakerHub _hub, List<Breaker> _breakers, int _intervalMs, int _concurrentBreakerCnt) {
hub = _hub; hub = _hub;
MCP3008Pin voltagePin = new MCP3008Pin(getChip(0), 0); GpioPinAnalogInput voltagePin = getPin(0, 0);
breakers = CollectionUtils.transform(_breakers, _b->{ breakers = CollectionUtils.transform(_breakers, _b->{
LOG.info("Getting Chip {}, Pin {} for port {}", _b.getChip(), _b.getPin(), _b.getPort()); LOG.info("Getting Chip {}, Pin {} for port {}", _b.getChip(), _b.getPin(), _b.getPort());
MCP3008Pin currentPin = new MCP3008Pin(getChip(_b.getChip()), _b.getPin()); GpioPinAnalogInput currentPin = getPin(_b.getChip(), _b.getPin());
List<BreakerSamples> batches = new ArrayList<>(BATCH_CNT); List<BreakerSamples> batches = new ArrayList<>(BATCH_CNT);
for (int i=0; i<BATCH_CNT; i++) { for (int i=0; i<BATCH_CNT; i++) {
List<PowerSample> samples = new ArrayList<>(30000/_breakers.size()); List<PowerSample> samples = new ArrayList<>(30000/_breakers.size());
for (int j=0; j<60000/_breakers.size(); j++) { for (int j=0; j<30000/_breakers.size(); j++) {
samples.add(new PowerSample()); samples.add(new PowerSample());
} }
batches.add(new BreakerSamples(_b, voltagePin, currentPin, samples)); batches.add(new BreakerSamples(_b, voltagePin, currentPin, samples));
@ -194,11 +213,6 @@ public class CurrentMonitor {
long start = System.nanoTime(); long start = System.nanoTime();
long interval = 0; long interval = 0;
int cycle; int cycle;
int curBreaker;
long intervalStart;
long intervalEnd;
long cycleEnd;
long curTime;
BreakerSamples[] cycleBreakers = new BreakerSamples[concurrentBreakerCnt]; BreakerSamples[] cycleBreakers = new BreakerSamples[concurrentBreakerCnt];
try { try {
while (true) { while (true) {
@ -209,83 +223,36 @@ public class CurrentMonitor {
} }
} }
final Date readTime = new Date(); final Date readTime = new Date();
intervalStart = (interval * intervalNs) + start; final long intervalStart = (interval * intervalNs) + start;
intervalEnd = intervalStart + intervalNs; long intervalEnd = intervalStart + intervalNs;
cycle = 0; cycle = 0;
final int batch = (int) (interval % BATCH_CNT); 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) { while (System.nanoTime() < intervalEnd) {
for (curBreaker = 0; curBreaker < concurrentBreakerCnt; curBreaker++) { for (curBreaker = 0; curBreaker < concurrentBreakerCnt; curBreaker++) {
cycleBreakers[curBreaker] = breakers.get(((cycle * concurrentBreakerCnt) + curBreaker) % breakers.size()).get(batch); cycleBreakers[curBreaker] = breakers.get(((cycle * concurrentBreakerCnt) + curBreaker) % breakers.size()).get(batch);
cycleBreakers[curBreaker].incrementCycleCnt();
} }
cycle++; cycle++;
cycleEnd = intervalStart + (cycle * (intervalNs / hub.getFrequency())); long cycleEnd = intervalStart + (cycle * (intervalNs / hub.getFrequency()));
curTime = System.nanoTime(); while (System.nanoTime() < cycleEnd) {
while (curTime < cycleEnd) {
for (curBreaker = 0; curBreaker < concurrentBreakerCnt; curBreaker++) { for (curBreaker = 0; curBreaker < concurrentBreakerCnt; curBreaker++) {
PowerSample sample = cycleBreakers[curBreaker].incrementSample(); PowerSample sample = cycleBreakers[curBreaker].getSample(cycleBreakers[curBreaker].getSampleCnt());
sample.nanoTime = curTime; sample.voltage = cycleBreakers[curBreaker].getVoltagePin().getValue();
sample.cycle = cycle; sample.current = cycleBreakers[curBreaker].getCurrentPin().getValue();
sample.voltage = cycleBreakers[curBreaker].getVoltagePin().read(); cycleBreakers[curBreaker].setSampleCnt(cycleBreakers[curBreaker].getSampleCnt()+1);
sample.current = cycleBreakers[curBreaker].getCurrentPin().read();
} }
curTime = System.nanoTime();
} }
} }
interval++; interval++;
final HubSample hubSample = (postSamples && (interval == 10)) ? new HubSample() : null;
executor.submit(() -> { executor.submit(() -> {
long cycleLength = 1000000000/hub.getFrequency();
if (hubSample != null) {
hubSample.setSampleDate(new Date());
hubSample.setBreakers(new ArrayList<>());
}
for (List<BreakerSamples> breaker : breakers) { for (List<BreakerSamples> breaker : breakers) {
BreakerSamples samples = breaker.get(batch);
List<PowerSample> validSamples = samples.getSamples().subList(0, samples.getSampleCnt());
if (hubSample != null) {
BreakerSample breakerSample = new BreakerSample();
breakerSample.setSamples(validSamples);
breakerSample.setPanel(samples.getBreaker().getPanel());
breakerSample.setSpace(samples.getBreaker().getSpace());
hubSample.getBreakers().add(breakerSample);
}
int phaseOffsetNs = samples.getBreaker().getPhaseOffsetNs()-hub.getPhaseOffsetNs();
if (phaseOffsetNs != 0) {
Map<Integer, List<PowerSample>> cycles = CollectionUtils.transformToMultiMap(validSamples, _p->_p.cycle);
for (List<PowerSample> cycleSamples : cycles.values()) {
long minNano;
long maxNano = minNano = cycleSamples.get(0).nanoTime;
for (PowerSample sample : cycleSamples) {
if (sample.nanoTime < minNano)
minNano = sample.nanoTime;
if (sample.nanoTime > maxNano)
maxNano = sample.nanoTime;
}
TreeMap<Long, Double> offsetSamples = new TreeMap<>();
for (PowerSample sample : cycleSamples) {
if (sample.nanoTime + phaseOffsetNs < minNano)
offsetSamples.put(sample.nanoTime + phaseOffsetNs + cycleLength, sample.voltage);
else if (sample.nanoTime + phaseOffsetNs > maxNano)
offsetSamples.put(sample.nanoTime + phaseOffsetNs - cycleLength, sample.voltage);
else
offsetSamples.put(sample.nanoTime + phaseOffsetNs, sample.voltage);
}
for (PowerSample sample : cycleSamples) {
List<Double> voltages = new ArrayList<>();
Entry<Long, Double> floorEntry = offsetSamples.floorEntry(sample.nanoTime);
if (floorEntry != null)
voltages.add(floorEntry.getValue());
Entry<Long, Double> ceilingEntry = offsetSamples.ceilingEntry(sample.nanoTime);
if (ceilingEntry != null)
voltages.add(ceilingEntry.getValue());
sample.voltage = CollectionUtils.mean(voltages);
}
}
}
double vOffset = 0.0; double vOffset = 0.0;
double iOffset = 0.0; double iOffset = 0.0;
BreakerSamples samples = breaker.get(batch);
List<PowerSample> validSamples = samples.getSamples().subList(0, samples.getSampleCnt());
for (PowerSample sample : validSamples) { for (PowerSample sample : validSamples) {
vOffset += sample.voltage; vOffset += sample.voltage;
iOffset += sample.current; iOffset += sample.current;
@ -296,7 +263,6 @@ public class CurrentMonitor {
double pSum = 0.0; double pSum = 0.0;
double vRms = 0.0; double vRms = 0.0;
double lowPassFilter = samples.getBreaker().getLowPassFilter(); double lowPassFilter = samples.getBreaker().getLowPassFilter();
for (PowerSample sample : validSamples) { for (PowerSample sample : validSamples) {
sample.current -= iOffset; sample.current -= iOffset;
if (Math.abs(sample.current) < lowPassFilter) if (Math.abs(sample.current) < lowPassFilter)
@ -307,26 +273,21 @@ public class CurrentMonitor {
} }
vRms /= validSamples.size(); vRms /= validSamples.size();
vRms = hub.getVoltageCalibrationFactor() * Math.sqrt(vRms); vRms = hub.getVoltageCalibrationFactor() * Math.sqrt(vRms);
int lowSampleRatio = (lowSamples * 100) / validSamples.size(); int lowSampleRatio = (lowSamples * 100) / samples.getSampleCnt();
double realPower = (hub.getVoltageCalibrationFactor() * hub.getPortCalibrationFactor() * samples.getBreaker().getFinalCalibrationFactor() * pSum) / validSamples.size(); double realPower = Math.abs((hub.getVoltageCalibrationFactor() * hub.getPortCalibrationFactor() * samples.getBreaker().getFinalCalibrationFactor() * pSum) / samples.getSampleCnt());
if ((lowSampleRatio > 75) && Math.abs(realPower) < 13.0) if ((lowSampleRatio > 75) && realPower < 13.0)
realPower = 0.0; realPower = 0.0;
if (samples.getBreaker().getPolarity() == BreakerPolarity.NORMAL) if (samples.getBreaker().getPolarity() == BreakerPolarity.SOLAR)
realPower = Math.abs(realPower);
else if (samples.getBreaker().getPolarity() == BreakerPolarity.SOLAR)
realPower = -Math.abs(realPower);
else if (samples.getBreaker().getPolarity() == BreakerPolarity.BI_DIRECTIONAL_INVERTED)
realPower = -realPower; realPower = -realPower;
if (samples.getBreaker().isDoublePower()) if (samples.getBreaker().isDoublePower())
realPower *= 2.0; realPower *= 2.0;
if (debug) { if (debug) {
synchronized (CurrentMonitor.this) { synchronized (CurrentMonitor.this) {
LOG.info("===========================Start Port {}", samples.getBreaker().getPort()); LOG.info("===========================Start Port {}", samples.getBreaker().getPort());
LOG.info("Cycles: {}", samples.getCycleCnt());
LOG.info("Samples: {}", samples.getSampleCnt()); 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("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)); 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 = hub.getPortCalibrationFactor() * samples.getBreaker().getFinalCalibrationFactor() * Math.sqrt(CollectionUtils.mean(CollectionUtils.transform(validSamples, _p -> _p.current * _p.current))); 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("vRms: {}", String.format("%.3f", vRms));
LOG.info("iRms: {}", String.format("%.3f", iRms)); LOG.info("iRms: {}", String.format("%.3f", iRms));
double apparentPower = vRms * iRms; double apparentPower = vRms * iRms;
@ -337,12 +298,8 @@ public class CurrentMonitor {
LOG.info("===========================End Port {}", samples.getBreaker().getPort()); LOG.info("===========================End Port {}", samples.getBreaker().getPort());
} }
} }
samples.setSampleCnt(0);
samples.setCycleCnt(0);
listener.onPowerEvent(new BreakerPower(samples.getBreaker().getPanel(), samples.getBreaker().getSpace(), readTime, realPower, vRms)); listener.onPowerEvent(new BreakerPower(samples.getBreaker().getPanel(), samples.getBreaker().getSpace(), readTime, realPower, vRms));
} }
if (hubSample != null)
listener.onSampleEvent(hubSample);
}); });
} }
} }

View File

@ -16,7 +16,6 @@ import com.lanternsoftware.datamodel.currentmonitor.HubConfigCharacteristic;
import com.lanternsoftware.datamodel.currentmonitor.HubConfigService; import com.lanternsoftware.datamodel.currentmonitor.HubConfigService;
import com.lanternsoftware.datamodel.currentmonitor.HubPowerMinute; import com.lanternsoftware.datamodel.currentmonitor.HubPowerMinute;
import com.lanternsoftware.datamodel.currentmonitor.NetworkStatus; import com.lanternsoftware.datamodel.currentmonitor.NetworkStatus;
import com.lanternsoftware.datamodel.currentmonitor.hub.HubSample;
import com.lanternsoftware.util.CollectionUtils; import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.NullUtils; import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.ResourceLoader; import com.lanternsoftware.util.ResourceLoader;
@ -36,9 +35,12 @@ import org.apache.http.entity.ContentType;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
import java.io.Console;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL; import java.net.URL;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.ArrayList; import java.util.ArrayList;
@ -66,24 +68,16 @@ public class MonitorApp {
private static final CurrentMonitor monitor = new CurrentMonitor(); private static final CurrentMonitor monitor = new CurrentMonitor();
private static final List<BreakerPower> readings = new ArrayList<>(); private static final List<BreakerPower> readings = new ArrayList<>();
private static String version; private static String version;
private static final PowerListener logger = new PowerListener() { private static final PowerListener logger = _p -> {
@Override if (!config.isDebug()) {
public void onPowerEvent(BreakerPower _power) { _p.setHubVersion(version);
if (!config.isDebug()) { if (breakerConfig != null)
_power.setHubVersion(version); _p.setAccountId(breakerConfig.getAccountId());
if (breakerConfig != null) synchronized (readings) {
_power.setAccountId(breakerConfig.getAccountId()); readings.add(_p);
synchronized (readings) { }
readings.add(_power); } else
} LOG.info("Panel{} - Space{} Power: {}W", _p.getPanel(), Breaker.toSpaceDisplay(_p.getSpace()), String.format("%.3f", _p.getPower()));
} else
LOG.info("Panel{} - Space{} Power: {}W", _power.getPanel(), Breaker.toSpaceDisplay(_power.getSpace()), String.format("%.3f", _power.getPower()));
}
@Override
public void onSampleEvent(HubSample _sample) {
post(DaoSerializer.toZipBson(_sample), "sample");
}
}; };
private static final BleCharacteristicListener bluetoothListener = new BleCharacteristicListener() { private static final BleCharacteristicListener bluetoothListener = new BleCharacteristicListener() {
@Override @Override
@ -216,15 +210,17 @@ public class MonitorApp {
version = getVersionNumber(); version = getVersionNumber();
config = DaoSerializer.parse(ResourceLoader.loadFileAsString(WORKING_DIR + "config.json"), MonitorConfig.class); config = DaoSerializer.parse(ResourceLoader.loadFileAsString(WORKING_DIR + "config.json"), MonitorConfig.class);
if (config == null) { if (config == null) {
config = new MonitorConfig(); LOG.error("Failed to load config file from {}", WORKING_DIR + "config.json");
ResourceLoader.writeFile(WORKING_DIR + "config.json", DaoSerializer.toJson(config)); return;
} }
pool = HttpPool.builder().withValidateSSLCertificates(!config.isAcceptSelfSignedCertificates()).build(); pool = new HttpPool(10, 10, config.getSocketTimeout(), config.getConnectTimeout(), config.getSocketTimeout());
if (NullUtils.isNotEmpty(config.getHost())) if (NullUtils.isNotEmpty(config.getHost()))
host = NullUtils.terminateWith(config.getHost(), "/"); host = NullUtils.terminateWith(config.getHost(), "/");
monitor.setDebug(config.isDebug()); monitor.setDebug(config.isDebug());
monitor.setPostSamples(config.isPostSamples()); monitor.start();
LEDFlasher.setLEDOn(false); LEDFlasher.setLEDOn(false);
bluetoothConfig = new BluetoothConfig("Lantern Hub", bluetoothListener);
bluetoothConfig.start();
if (NullUtils.isNotEmpty(config.getAuthCode())) if (NullUtils.isNotEmpty(config.getAuthCode()))
authCode = config.getAuthCode(); authCode = config.getAuthCode();
else if (NullUtils.isNotEmpty(host) && NullUtils.isNotEmpty(config.getUsername()) && NullUtils.isNotEmpty(config.getPassword())) { else if (NullUtils.isNotEmpty(host) && NullUtils.isNotEmpty(config.getUsername()) && NullUtils.isNotEmpty(config.getPassword())) {
@ -235,8 +231,7 @@ public class MonitorApp {
if (NullUtils.isNotEmpty(config.getMqttBrokerUrl())) if (NullUtils.isNotEmpty(config.getMqttBrokerUrl()))
mqttPoster = new MqttPoster(config); mqttPoster = new MqttPoster(config);
if (NullUtils.isNotEmpty(host) && NullUtils.isNotEmpty(authCode)) { if (NullUtils.isNotEmpty(host) && NullUtils.isNotEmpty(authCode)) {
int configAttempts = 0; while (true) {
while (configAttempts < 5) {
HttpGet get = new HttpGet(host + "config"); HttpGet get = new HttpGet(host + "config");
get.addHeader("auth_code", authCode); get.addHeader("auth_code", authCode);
breakerConfig = DaoSerializer.parse(pool.executeToString(get), BreakerConfig.class); breakerConfig = DaoSerializer.parse(pool.executeToString(get), BreakerConfig.class);
@ -244,11 +239,8 @@ public class MonitorApp {
break; break;
LOG.error("Failed to load breaker config. Retrying in 5 seconds..."); LOG.error("Failed to load breaker config. Retrying in 5 seconds...");
ConcurrencyUtils.sleep(5000); ConcurrencyUtils.sleep(5000);
configAttempts++;
} }
} }
bluetoothConfig = new BluetoothConfig("Lantern Hub", bluetoothListener);
bluetoothConfig.start();
if ((mqttPoster != null) && (breakerConfig == null)) { if ((mqttPoster != null) && (breakerConfig == null)) {
LOG.info("Hub not configured by a Lantern Power Monitor server, defaulting to MQTT mode only"); LOG.info("Hub not configured by a Lantern Power Monitor server, defaulting to MQTT mode only");
BreakerHub hub = new BreakerHub(); BreakerHub hub = new BreakerHub();
@ -274,18 +266,13 @@ public class MonitorApp {
BreakerHub hub = breakerConfig.getHub(config.getHub()); BreakerHub hub = breakerConfig.getHub(config.getHub());
if (hub != null) { if (hub != null) {
if (config.isNeedsCalibration()) { if (config.isNeedsCalibration()) {
try { CalibrationResult cal = monitor.calibrateVoltage(hub.getVoltageCalibrationFactor());
CalibrationResult cal = monitor.calibrateVoltage(hub.getVoltageCalibrationFactor()); if (cal != null) {
if (cal != null) { hub.setVoltageCalibrationFactor(cal.getVoltageCalibrationFactor());
hub.setVoltageCalibrationFactor(cal.getVoltageCalibrationFactor()); hub.setFrequency(cal.getFrequency());
hub.setFrequency(cal.getFrequency()); config.setNeedsCalibration(false);
config.setNeedsCalibration(false); ResourceLoader.writeFile(WORKING_DIR + "config.json", DaoSerializer.toJson(config));
ResourceLoader.writeFile(WORKING_DIR + "config.json", DaoSerializer.toJson(config)); post(DaoSerializer.toZipBson(breakerConfig), "config");
post(DaoSerializer.toZipBson(breakerConfig), "config");
}
}
catch (Throwable t) {
LOG.error("Exception trying to read from voltage pin", t);
} }
} }
List<Breaker> breakers = breakerConfig.getBreakersForHub(config.getHub()); List<Breaker> breakers = breakerConfig.getBreakersForHub(config.getHub());
@ -301,11 +288,17 @@ public class MonitorApp {
monitor.stop(); monitor.stop();
pool.shutdown(); pool.shutdown();
}, "Monitor Shutdown")); }, "Monitor Shutdown"));
synchronized (monitor) { Console c = System.console();
BufferedReader reader = (c == null)?new BufferedReader(new InputStreamReader(System.in)):null;
while (running.get()) {
try { try {
monitor.wait(); String command = c != null ? c.readLine() : reader.readLine();
} catch (InterruptedException _e) { if (NullUtils.isEqual("exit", command))
LOG.error("Interrupted, shutting down", _e); break;
}
catch (Exception _e) {
LOG.error("Exception while reading from console input", _e);
break;
} }
} }
} }
@ -367,7 +360,7 @@ public class MonitorApp {
byte[] payload = DaoSerializer.toZipBson(minutePost); byte[] payload = DaoSerializer.toZipBson(minutePost);
if (!post(payload, "power/hub")) { if (!post(payload, "power/hub")) {
LOG.info("Failed Posting HubPowerMinute, writing cache"); LOG.info("Failed Posting HubPowerMinute, writing cache");
ResourceLoader.writeFile(WORKING_DIR + "cache/" + UUID.randomUUID() + ".min", payload); ResourceLoader.writeFile(WORKING_DIR + "cache/" + UUID.randomUUID().toString() + ".min", payload);
} }
} }
if (post != null) { if (post != null) {

View File

@ -2,7 +2,6 @@ package com.lanternsoftware.currentmonitor;
import com.lanternsoftware.datamodel.currentmonitor.Breaker; import com.lanternsoftware.datamodel.currentmonitor.Breaker;
import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.dao.annotations.DBSerializable; import com.lanternsoftware.util.dao.annotations.DBSerializable;
import java.util.List; import java.util.List;
@ -13,13 +12,11 @@ public class MonitorConfig {
private String authCode; private String authCode;
private String username; private String username;
private String password; private String password;
private int hub = -1; private int hub;
private boolean debug; private boolean debug;
private int connectTimeout; private int connectTimeout;
private int socketTimeout; private int socketTimeout;
private boolean postSamples = false; private boolean needsCalibration;
private boolean needsCalibration = true;
private boolean acceptSelfSignedCertificates = false;
private String mqttBrokerUrl; private String mqttBrokerUrl;
private String mqttUserName; private String mqttUserName;
private String mqttPassword; private String mqttPassword;
@ -37,7 +34,7 @@ public class MonitorConfig {
} }
public String getHost() { public String getHost() {
return NullUtils.isEmpty(host) ? "https://lanternpowermonitor.com/currentmonitor/" : host; return host;
} }
public void setHost(String _host) { public void setHost(String _host) {
@ -100,14 +97,6 @@ public class MonitorConfig {
socketTimeout = _socketTimeout; socketTimeout = _socketTimeout;
} }
public boolean isPostSamples() {
return postSamples;
}
public void setPostSamples(boolean _postSamples) {
postSamples = _postSamples;
}
public boolean isNeedsCalibration() { public boolean isNeedsCalibration() {
return needsCalibration; return needsCalibration;
} }
@ -116,14 +105,6 @@ public class MonitorConfig {
needsCalibration = _needsCalibration; needsCalibration = _needsCalibration;
} }
public boolean isAcceptSelfSignedCertificates() {
return acceptSelfSignedCertificates;
}
public void setAcceptSelfSignedCertificates(boolean _acceptSelfSignedCertificates) {
acceptSelfSignedCertificates = _acceptSelfSignedCertificates;
}
public String getMqttBrokerUrl() { public String getMqttBrokerUrl() {
return mqttBrokerUrl; return mqttBrokerUrl;
} }

View File

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

View File

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

View File

@ -1,29 +0,0 @@
package com.lanternsoftware.currentmonitor.adc;
import com.lanternsoftware.pigpio.Spi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MCP3008 {
protected static final Logger LOG = LoggerFactory.getLogger(MCP3008.class);
private static final byte[][] pins = new byte[8][];
private final Spi spi;
private final byte[] resp = new byte[3];
static {
for (int p = 0; p < 8; p++) {
pins[p] = new byte[]{1,(byte)(p + 8 << 4),0};
}
}
public MCP3008(Spi _spi) {
spi = _spi;
}
public int readPin(int _pin) {
if (spi != null && spi.transfer(pins[_pin], resp) > 2)
return ((resp[1] & 0x03) << 8) + (resp[2] & 0xFF);
return 0;
}
}

View File

@ -1,15 +0,0 @@
package com.lanternsoftware.currentmonitor.adc;
public class MCP3008Pin {
private final MCP3008 chip;
private final int pin;
public MCP3008Pin(MCP3008 _chip, int _pin) {
chip = _chip;
pin = _pin;
}
public int read() {
return chip.readPin(pin);
}
}

View File

@ -34,9 +34,7 @@ public class MonitorConfigSerializer extends AbstractDaoSerializer<MonitorConfig
d.put("debug", _o.isDebug()); d.put("debug", _o.isDebug());
d.put("connect_timeout", _o.getConnectTimeout()); d.put("connect_timeout", _o.getConnectTimeout());
d.put("socket_timeout", _o.getSocketTimeout()); d.put("socket_timeout", _o.getSocketTimeout());
d.put("post_samples", _o.isPostSamples());
d.put("needs_calibration", _o.isNeedsCalibration()); d.put("needs_calibration", _o.isNeedsCalibration());
d.put("accept_self_signed_certificates", _o.isAcceptSelfSignedCertificates());
d.put("mqtt_broker_url", _o.getMqttBrokerUrl()); d.put("mqtt_broker_url", _o.getMqttBrokerUrl());
d.put("mqtt_user_name", _o.getMqttUserName()); d.put("mqtt_user_name", _o.getMqttUserName());
d.put("mqtt_password", _o.getMqttPassword()); d.put("mqtt_password", _o.getMqttPassword());
@ -59,9 +57,7 @@ public class MonitorConfigSerializer extends AbstractDaoSerializer<MonitorConfig
o.setDebug(DaoSerializer.getBoolean(_d, "debug")); o.setDebug(DaoSerializer.getBoolean(_d, "debug"));
o.setConnectTimeout(DaoSerializer.getInteger(_d, "connect_timeout")); o.setConnectTimeout(DaoSerializer.getInteger(_d, "connect_timeout"));
o.setSocketTimeout(DaoSerializer.getInteger(_d, "socket_timeout")); o.setSocketTimeout(DaoSerializer.getInteger(_d, "socket_timeout"));
o.setPostSamples(DaoSerializer.getBoolean(_d, "post_samples"));
o.setNeedsCalibration(DaoSerializer.getBoolean(_d, "needs_calibration")); o.setNeedsCalibration(DaoSerializer.getBoolean(_d, "needs_calibration"));
o.setAcceptSelfSignedCertificates(DaoSerializer.getBoolean(_d, "accept_self_signed_certificates"));
o.setMqttBrokerUrl(DaoSerializer.getString(_d, "mqtt_broker_url")); o.setMqttBrokerUrl(DaoSerializer.getString(_d, "mqtt_broker_url"));
o.setMqttUserName(DaoSerializer.getString(_d, "mqtt_user_name")); o.setMqttUserName(DaoSerializer.getString(_d, "mqtt_user_name"));
o.setMqttPassword(DaoSerializer.getString(_d, "mqtt_password")); o.setMqttPassword(DaoSerializer.getString(_d, "mqtt_password"));

View File

@ -2,6 +2,12 @@
<configuration> <configuration>
<property name="log.pattern" value="%date %-5level %logger{0} - %message%n"/> <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"> <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/opt/currentmonitor/log/log.txt</file> <file>/opt/currentmonitor/log/log.txt</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
@ -15,7 +21,6 @@
</appender> </appender>
<logger name="com.lanternsoftware" level="INFO"/> <logger name="com.lanternsoftware" level="INFO"/>
<logger name="com.pi4j" level="INFO"/>
<root level="OFF"> <root level="OFF">
<appender-ref ref="FILE"/> <appender-ref ref="FILE"/>

View File

@ -1,31 +1,31 @@
<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"> <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> <modelVersion>4.0.0</modelVersion>
<groupId>com.lanternsoftware.currentmonitor</groupId>
<artifactId>lantern-dataaccess-currentmonitor</artifactId> <artifactId>lantern-dataaccess-currentmonitor</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<version>1.1.0</version> <version>1.0.0</version>
<name>lantern-dataaccess-currentmonitor</name> <name>lantern-dataaccess-currentmonitor</name>
<parent> <properties>
<groupId>com.lanternsoftware.currentmonitor</groupId> <maven.compiler.source>1.8</maven.compiler.source>
<artifactId>currentmonitor</artifactId> <maven.compiler.target>1.8</maven.compiler.target>
<version>1.1.0</version> </properties>
</parent>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>com.lanternsoftware.currentmonitor</groupId> <groupId>com.lanternsoftware.currentmonitor</groupId>
<artifactId>lantern-datamodel-currentmonitor</artifactId> <artifactId>lantern-datamodel-currentmonitor</artifactId>
<version>${cm.version}</version> <version>1.0.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.lanternsoftware.rules</groupId> <groupId>com.lanternsoftware.rules</groupId>
<artifactId>lantern-datamodel-rules</artifactId> <artifactId>lantern-datamodel-rules</artifactId>
<version>${rules.version}</version> <version>1.0.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.lanternsoftware.util</groupId> <groupId>com.lanternsoftware.util</groupId>
<artifactId>lantern-util-dao-mongo</artifactId> <artifactId>lantern-util-dao-mongo</artifactId>
<version>${util.version}</version> <version>1.0.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.mindrot</groupId> <groupId>org.mindrot</groupId>
@ -43,7 +43,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version> <version>3.2</version>
<executions> <executions>
<execution> <execution>
<goals> <goals>
@ -56,14 +56,14 @@
<optimize>true</optimize> <optimize>true</optimize>
<showDeprecation>true</showDeprecation> <showDeprecation>true</showDeprecation>
<encoding>UTF-8</encoding> <encoding>UTF-8</encoding>
<source>${maven.compiler.source}</source> <source>1.8</source>
<target>${maven.compiler.target}</target> <target>1.8</target>
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId> <artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version> <version>2.4</version>
<executions> <executions>
<execution> <execution>
<phase>package</phase> <phase>package</phase>
@ -73,6 +73,16 @@
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.5</version>
<configuration>
<archive>
<index>true</index>
</archive>
</configuration>
</plugin>
</plugins> </plugins>
</build> </build>
</project> </project>

View File

@ -4,31 +4,22 @@ import com.lanternsoftware.datamodel.currentmonitor.Account;
import com.lanternsoftware.datamodel.currentmonitor.HubPowerMinute; import com.lanternsoftware.datamodel.currentmonitor.HubPowerMinute;
import com.lanternsoftware.util.DateUtils; import com.lanternsoftware.util.DateUtils;
import com.lanternsoftware.util.DebugTimer; import com.lanternsoftware.util.DebugTimer;
import com.lanternsoftware.util.concurrency.ConcurrencyUtils;
import com.lanternsoftware.util.external.LanternFiles; import com.lanternsoftware.util.external.LanternFiles;
import com.lanternsoftware.util.NullUtils; import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.dao.DaoQuery; import com.lanternsoftware.util.dao.DaoQuery;
import com.lanternsoftware.util.dao.DaoSort; import com.lanternsoftware.util.dao.DaoSort;
import com.lanternsoftware.util.dao.mongo.MongoConfig; import com.lanternsoftware.util.dao.mongo.MongoConfig;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class BackupMinutes { public class BackupMinutes {
public static void main(String[] args) { public static void main(String[] args) {
CurrentMonitorDao sourceDao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.CONFIG_PATH + "mongo.cfg")); CurrentMonitorDao dao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.CONFIG_PATH + "mongo.cfg"));
CurrentMonitorDao destDao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.BACKUP_DEST_PATH + "mongo.cfg")); CurrentMonitorDao backupDao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.BACKUP_DEST_PATH + "mongo.cfg"));
ExecutorService ex = Executors.newFixedThreadPool(8); Date now = new Date();
List<Future<?>> tasks = new ArrayList<>(); for (Account a : dao.getProxy().queryAll(Account.class)) {
for (Account a : sourceDao.getProxy().queryAll(Account.class)) {
if (a.getId() == 0) if (a.getId() == 0)
continue; continue;
DebugTimer t = new DebugTimer("Account " + a.getId()); DebugTimer t = new DebugTimer("Account " + a.getId());
@ -36,35 +27,28 @@ public class BackupMinutes {
a.setTimezone("America/Chicago"); a.setTimezone("America/Chicago");
} }
TimeZone tz = TimeZone.getTimeZone(a.getTimezone()); TimeZone tz = TimeZone.getTimeZone(a.getTimezone());
HubPowerMinute firstMinute = sourceDao.getProxy().queryOne(HubPowerMinute.class, new DaoQuery("account_id", a.getId()), DaoSort.sort("minute")); HubPowerMinute minute = dao.getProxy().queryOne(HubPowerMinute.class, new DaoQuery("account_id", a.getId()), DaoSort.sort("minute"));
if (firstMinute == null) if (minute == null)
continue; continue;
HubPowerMinute lastMinute = sourceDao.getProxy().queryOne(HubPowerMinute.class, new DaoQuery("account_id", a.getId()), DaoSort.sortDesc("minute")); HubPowerMinute lastBackup = backupDao.getProxy().queryOne(HubPowerMinute.class, new DaoQuery("account_id", a.getId()), DaoSort.sortDesc("minute"));
HubPowerMinute lastBackup = destDao.getProxy().queryOne(HubPowerMinute.class, new DaoQuery("account_id", a.getId()), DaoSort.sortDesc("minute")); Date start = lastBackup == null ? DateUtils.getMidnightBefore(minute.getMinuteAsDate(), tz) : lastBackup.getMinuteAsDate();
Date start = lastBackup == null ? DateUtils.getMidnightBefore(firstMinute.getMinuteAsDate(), tz) : lastBackup.getMinuteAsDate(); // Date start = DateUtils.date(10,16,2021,tz);
Date lastMin = lastMinute.getMinuteAsDate();
Date end = DateUtils.addDays(start, 1, tz); Date end = DateUtils.addDays(start, 1, tz);
while (start.before(lastMin)) { while (start.before(now)) {
final Date curStart = start; DebugTimer t2 = new DebugTimer("Account Id: " + a.getId() + " Query Day " + DateUtils.format("MM/dd/yyyy", tz, start));
final Date curEnd = end; List<HubPowerMinute> minutes = dao.getProxy().query(HubPowerMinute.class, new DaoQuery("account_id", a.getId()).andBetweenInclusiveExclusive("minute", (int) (start.getTime() / 60000), (int) (end.getTime() / 60000)));
tasks.add(ex.submit(() -> { t2.stop();
DebugTimer t2 = new DebugTimer("Account Id: " + a.getId() + " Query Day " + DateUtils.format("MM/dd/yyyy", tz, curStart)); if (!minutes.isEmpty()) {
List<HubPowerMinute> minutes = sourceDao.getProxy().query(HubPowerMinute.class, new DaoQuery("account_id", a.getId()).andBetweenInclusiveExclusive("minute", (int) (curStart.getTime() / 60000), (int) (curEnd.getTime() / 60000))); DebugTimer t3 = new DebugTimer("Save Day");
t2.stop(); backupDao.getProxy().save(minutes);
if (!minutes.isEmpty()) { t3.stop();
DebugTimer t3 = new DebugTimer("Save Day"); }
destDao.getProxy().save(minutes);
t3.stop();
}
}));
start = end; start = end;
end = DateUtils.addDays(end, 1, tz); end = DateUtils.addDays(end, 1, tz);
} }
t.stop(); t.stop();
} }
ConcurrencyUtils.getAll(tasks); dao.shutdown();
ex.shutdown(); backupDao.shutdown();
sourceDao.shutdown();
destDao.shutdown();
} }
} }

View File

@ -8,7 +8,6 @@ import com.lanternsoftware.datamodel.currentmonitor.EnergyViewMode;
import com.lanternsoftware.datamodel.currentmonitor.HubCommand; import com.lanternsoftware.datamodel.currentmonitor.HubCommand;
import com.lanternsoftware.datamodel.currentmonitor.HubPowerMinute; import com.lanternsoftware.datamodel.currentmonitor.HubPowerMinute;
import com.lanternsoftware.datamodel.currentmonitor.archive.ArchiveStatus; import com.lanternsoftware.datamodel.currentmonitor.archive.ArchiveStatus;
import com.lanternsoftware.datamodel.currentmonitor.hub.HubSample;
import com.lanternsoftware.util.DateRange; import com.lanternsoftware.util.DateRange;
import com.lanternsoftware.util.dao.auth.AuthCode; import com.lanternsoftware.util.dao.auth.AuthCode;
import com.lanternsoftware.util.dao.mongo.MongoProxy; import com.lanternsoftware.util.dao.mongo.MongoProxy;
@ -45,6 +44,7 @@ public interface CurrentMonitorDao {
void putConfig(BreakerConfig _config); void putConfig(BreakerConfig _config);
void rebuildSummaries(int _accountId); void rebuildSummaries(int _accountId);
void rebuildSummariesAsync(int _accountId);
void rebuildSummaries(int _accountId, Date _start, Date _end); void rebuildSummaries(int _accountId, Date _start, Date _end);
String addPasswordResetKey(String _email); String addPasswordResetKey(String _email);
@ -54,7 +54,6 @@ public interface CurrentMonitorDao {
String getAuthCodeForEmail(String _email, TimeZone _tz); String getAuthCodeForEmail(String _email, TimeZone _tz);
Account authCodeToAccount(String _authCode); Account authCodeToAccount(String _authCode);
AuthCode decryptAuthCode(String _authCode); AuthCode decryptAuthCode(String _authCode);
String exchangeAuthCode(String _authCode, int _acctId);
Account putAccount(Account _account); Account putAccount(Account _account);
Account getAccount(int _accountId); Account getAccount(int _accountId);
@ -66,8 +65,5 @@ public interface CurrentMonitorDao {
List<HubCommand> getAllHubCommands(); List<HubCommand> getAllHubCommands();
void deleteHubCommand(String _id); void deleteHubCommand(String _id);
void putHubSample(HubSample _sample);
List<HubSample> getSamplesForAccount(int _accountId);
MongoProxy getProxy(); MongoProxy getProxy();
} }

View File

@ -21,7 +21,6 @@ import com.lanternsoftware.datamodel.currentmonitor.archive.ArchiveStatus;
import com.lanternsoftware.datamodel.currentmonitor.archive.BreakerEnergyArchive; import com.lanternsoftware.datamodel.currentmonitor.archive.BreakerEnergyArchive;
import com.lanternsoftware.datamodel.currentmonitor.archive.DailyEnergyArchive; import com.lanternsoftware.datamodel.currentmonitor.archive.DailyEnergyArchive;
import com.lanternsoftware.datamodel.currentmonitor.archive.MonthlyEnergyArchive; import com.lanternsoftware.datamodel.currentmonitor.archive.MonthlyEnergyArchive;
import com.lanternsoftware.datamodel.currentmonitor.hub.HubSample;
import com.lanternsoftware.util.CollectionUtils; import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.DateRange; import com.lanternsoftware.util.DateRange;
import com.lanternsoftware.util.DateUtils; import com.lanternsoftware.util.DateUtils;
@ -91,9 +90,6 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
updateEnergySummaries(minute); updateEnergySummaries(minute);
} }
proxy.delete(DirtyMinute.class, new DaoQuery()); proxy.delete(DirtyMinute.class, new DaoQuery());
if (!proxy.exists(Sequence.class, null)) {
proxy.save(new Sequence());
}
} }
public void shutdown() { public void shutdown() {
@ -307,7 +303,7 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
TimeZone tz = getTimeZoneForAccount(_accountId); TimeZone tz = getTimeZoneForAccount(_accountId);
Date month = DateUtils.getStartOfMonth(range.getStart(), tz); Date month = DateUtils.getStartOfMonth(range.getStart(), tz);
Date end = DateUtils.getEndOfMonth(range.getEnd(), tz); Date end = DateUtils.getEndOfMonth(range.getEnd(), tz);
while ((month != null) && month.before(end)) { while (month.before(end)) {
statuses.computeIfAbsent(month, _m->new ArchiveStatus(_accountId, _m, 0)); statuses.computeIfAbsent(month, _m->new ArchiveStatus(_accountId, _m, 0));
month = DateUtils.addMonths(month, 1, tz); month = DateUtils.addMonths(month, 1, tz);
} }
@ -330,8 +326,6 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
TimeZone tz = getTimeZoneForAccount(_minute.getAccountId()); TimeZone tz = getTimeZoneForAccount(_minute.getAccountId());
BreakerConfig config = getConfig(_minute.getAccountId()); BreakerConfig config = getConfig(_minute.getAccountId());
BreakerGroup group = CollectionUtils.getFirst(config.getBreakerGroups()); BreakerGroup group = CollectionUtils.getFirst(config.getBreakerGroups());
if (group == null)
return;
Date day = DateUtils.getMidnightBefore(_minute.getMinuteAsDate(), tz); Date day = DateUtils.getMidnightBefore(_minute.getMinuteAsDate(), tz);
DebugTimer t2 = new DebugTimer("Updating energy", logger); DebugTimer t2 = new DebugTimer("Updating energy", logger);
EnergySummary energy = getEnergySummary(_minute.getAccountId(), group.getId(), EnergyViewMode.DAY, day); EnergySummary energy = getEnergySummary(_minute.getAccountId(), group.getId(), EnergyViewMode.DAY, day);
@ -418,13 +412,13 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
putEnergySummary(summary); putEnergySummary(summary);
} }
public void updateChargeSummary(BreakerConfig _config, EnergySummary _energySummary, TimeZone _tz) { private void updateChargeSummary(BreakerConfig _config, EnergySummary _energySummary, TimeZone _tz) {
Date lookback = null; Date lookback = null;
for (BillingPlan p : CollectionUtils.makeNotNull(_config.getBillingPlans())) { for (BillingPlan p : CollectionUtils.makeNotNull(_config.getBillingPlans())) {
Date cycleStart = p.getBillingCycleStart(_energySummary.getStart(), _tz); Date cycleStart = p.getBillingCycleStart(_energySummary.getStart(), _tz);
if (cycleStart.after(_energySummary.getStart())) if (cycleStart.after(_energySummary.getStart()))
cycleStart = DateUtils.addMonths(cycleStart, -1, _tz); cycleStart = DateUtils.addMonths(cycleStart, -1, _tz);
if ((lookback == null) || ((cycleStart != null) && cycleStart.before(lookback))) if ((lookback == null) || cycleStart.before(lookback))
lookback = cycleStart; lookback = cycleStart;
} }
if (lookback != null) { if (lookback != null) {
@ -468,7 +462,7 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
Date yearMonthStart = yearStart; Date yearMonthStart = yearStart;
Set<String> monthSummaryIds = new HashSet<>(); Set<String> monthSummaryIds = new HashSet<>();
Date loopEnd = DateUtils.addDays(yearEnd, 1, _tz); Date loopEnd = DateUtils.addDays(yearEnd, 1, _tz);
while ((yearMonthStart != null) && yearMonthStart.before(loopEnd)) { while (yearMonthStart.before(loopEnd)) {
Date billingStart = plan.getBillingCycleStart(yearMonthStart, _tz); Date billingStart = plan.getBillingCycleStart(yearMonthStart, _tz);
if (DateUtils.isBetween(billingStart, yearStart, yearEnd)) if (DateUtils.isBetween(billingStart, yearStart, yearEnd))
monthSummaryIds.add(ChargeSummary.toId(rootGroup.getAccountId(), plan.getPlanId(), rootGroup.getId(), EnergyViewMode.MONTH, billingStart)); monthSummaryIds.add(ChargeSummary.toId(rootGroup.getAccountId(), plan.getPlanId(), rootGroup.getId(), EnergyViewMode.MONTH, billingStart));
@ -488,13 +482,17 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
} }
} }
@Override
public void rebuildSummariesAsync(int _accountId) {
executor.submit(() -> rebuildSummaries(_accountId));
}
@Override @Override
public void rebuildSummaries(int _accountId) { public void rebuildSummaries(int _accountId) {
HubPowerMinute firstMinute = proxy.queryOne(HubPowerMinute.class, new DaoQuery("account_id", _accountId), DaoSort.sort("minute")); HubPowerMinute firstMinute = proxy.queryOne(HubPowerMinute.class, new DaoQuery("account_id", _accountId), DaoSort.sort("minute"));
if (firstMinute == null) if (firstMinute == null)
return; return;
HubPowerMinute lastMinute = proxy.queryOne(HubPowerMinute.class, new DaoQuery("account_id", _accountId), DaoSort.sortDesc("minute")); rebuildSummaries(_accountId, firstMinute.getMinuteAsDate(), new Date());
rebuildSummaries(_accountId, firstMinute.getMinuteAsDate(), lastMinute.getMinuteAsDate());
} }
@Override @Override
@ -662,7 +660,7 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
if (NullUtils.isEmpty(_username) || NullUtils.isEmpty(_password)) if (NullUtils.isEmpty(_username) || NullUtils.isEmpty(_password))
return null; return null;
Account acct = proxy.queryOne(Account.class, new DaoQuery("username", _username.toLowerCase().trim())); Account acct = proxy.queryOne(Account.class, new DaoQuery("username", _username.toLowerCase().trim()));
if ((acct == null) || !BCrypt.checkpw(_password, NullUtils.makeNotNull(acct.getPassword()))) if ((acct == null) || !BCrypt.checkpw(_password, acct.getPassword()))
return null; return null;
return toAuthCode(acct.getId(), acct.getAuxiliaryAccountIds()); return toAuthCode(acct.getId(), acct.getAuxiliaryAccountIds());
} }
@ -693,11 +691,6 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
return (account == null)?null:toAuthCode(account.getId(), account.getAuxiliaryAccountIds()); return (account == null)?null:toAuthCode(account.getId(), account.getAuxiliaryAccountIds());
} }
@Override
public String exchangeAuthCode(String _authCode, int _acctId) {
return null;
}
public String toAuthCode(int _acctId, List<Integer> _auxAcctIds) { public String toAuthCode(int _acctId, List<Integer> _auxAcctIds) {
if (_acctId < 1) if (_acctId < 1)
return null; return null;
@ -784,8 +777,6 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
if (entity == null) if (entity == null)
return false; return false;
Account acct = getAccountByUsername(aes.decryptFromBase64ToString(_key)); Account acct = getAccountByUsername(aes.decryptFromBase64ToString(_key));
if (acct == null)
return false;
acct.setPassword(_password); acct.setPassword(_password);
putAccount(acct); putAccount(acct);
proxy.delete("password_reset", new DaoQuery("_id", _key)); proxy.delete("password_reset", new DaoQuery("_id", _key));
@ -809,16 +800,6 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
proxy.delete(HubCommand.class, new DaoQuery("_id", _id)); proxy.delete(HubCommand.class, new DaoQuery("_id", _id));
} }
@Override
public void putHubSample(HubSample _sample) {
proxy.save(_sample);
}
@Override
public List<HubSample> getSamplesForAccount(int _accountId) {
return proxy.query(HubSample.class, new DaoQuery("account_id", _accountId));
}
@Override @Override
public MongoProxy getProxy() { public MongoProxy getProxy() {
return proxy; return proxy;

View File

@ -1,21 +1,21 @@
<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"> <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> <modelVersion>4.0.0</modelVersion>
<groupId>com.lanternsoftware.currentmonitor</groupId>
<artifactId>lantern-datamodel-currentmonitor</artifactId> <artifactId>lantern-datamodel-currentmonitor</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<version>1.1.0</version> <version>1.0.0</version>
<name>lantern-datamodel-currentmonitor</name> <name>lantern-datamodel-currentmonitor</name>
<parent> <properties>
<groupId>com.lanternsoftware.currentmonitor</groupId> <maven.compiler.source>1.8</maven.compiler.source>
<artifactId>currentmonitor</artifactId> <maven.compiler.target>1.8</maven.compiler.target>
<version>1.1.0</version> </properties>
</parent>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>com.lanternsoftware.util</groupId> <groupId>com.lanternsoftware.util</groupId>
<artifactId>lantern-util-dao</artifactId> <artifactId>lantern-util-dao</artifactId>
<version>${util.version}</version> <version>1.0.0</version>
</dependency> </dependency>
</dependencies> </dependencies>
<build> <build>
@ -28,7 +28,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version> <version>3.2</version>
<executions> <executions>
<execution> <execution>
<goals> <goals>
@ -41,14 +41,14 @@
<optimize>true</optimize> <optimize>true</optimize>
<showDeprecation>true</showDeprecation> <showDeprecation>true</showDeprecation>
<encoding>UTF-8</encoding> <encoding>UTF-8</encoding>
<source>${maven.compiler.source}</source> <source>1.8</source>
<target>${maven.compiler.target}</target> <target>1.8</target>
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId> <artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version> <version>2.4</version>
<executions> <executions>
<execution> <execution>
<phase>package</phase> <phase>package</phase>
@ -58,6 +58,16 @@
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.5</version>
<configuration>
<archive>
<index>true</index>
</archive>
</configuration>
</plugin>
</plugins> </plugins>
</build> </build>
</project> </project>

View File

@ -21,13 +21,11 @@ public class Breaker implements IIdentical<Breaker> {
private String name; private String name;
private String description; private String description;
private int sizeAmps; private int sizeAmps;
private int phaseOffsetNs;
private double calibrationFactor; private double calibrationFactor;
private double lowPassFilter; private double lowPassFilter;
private BreakerPolarity polarity; private BreakerPolarity polarity;
private boolean doublePower; private boolean doublePower;
private BreakerType type; private BreakerType type;
private boolean main;
private transient String key; private transient String key;
public Breaker() { public Breaker() {
@ -141,14 +139,6 @@ public class Breaker implements IIdentical<Breaker> {
sizeAmps = _sizeAmps; sizeAmps = _sizeAmps;
} }
public int getPhaseOffsetNs() {
return phaseOffsetNs;
}
public void setPhaseOffsetNs(int _phaseOffsetNs) {
phaseOffsetNs = _phaseOffsetNs;
}
public double getLowPassFilter() { public double getLowPassFilter() {
return Math.abs(lowPassFilter) < 0.05 ? 1.6 : lowPassFilter; return Math.abs(lowPassFilter) < 0.05 ? 1.6 : lowPassFilter;
} }
@ -158,7 +148,7 @@ public class Breaker implements IIdentical<Breaker> {
} }
public BreakerPolarity getPolarity() { public BreakerPolarity getPolarity() {
return polarity == null ? BreakerPolarity.NORMAL : polarity; return polarity;
} }
public void setPolarity(BreakerPolarity _polarity) { public void setPolarity(BreakerPolarity _polarity) {
@ -194,14 +184,6 @@ public class Breaker implements IIdentical<Breaker> {
type = _type; type = _type;
} }
public boolean isMain() {
return main;
}
public void setMain(boolean _main) {
main = _main;
}
public double getFinalCalibrationFactor() { public double getFinalCalibrationFactor() {
return getCalibrationFactor() * getSizeAmps() / 380.0; return getCalibrationFactor() * getSizeAmps() / 380.0;
} }
@ -287,7 +269,7 @@ public class Breaker implements IIdentical<Breaker> {
@Override @Override
public boolean isIdentical(Breaker _o) { public boolean isIdentical(Breaker _o) {
if (this == _o) return true; if (this == _o) return true;
return panel == _o.panel && space == _o.space && meter == _o.meter && hub == _o.hub && port == _o.port && sizeAmps == _o.sizeAmps && phaseOffsetNs == _o.phaseOffsetNs && Double.compare(_o.calibrationFactor, calibrationFactor) == 0 && Double.compare(_o.lowPassFilter, lowPassFilter) == 0 && doublePower == _o.doublePower && Objects.equals(name, _o.name) && Objects.equals(description, _o.description) && polarity == _o.polarity && type == _o.type; return panel == _o.panel && space == _o.space && meter == _o.meter && hub == _o.hub && port == _o.port && sizeAmps == _o.sizeAmps && Double.compare(_o.calibrationFactor, calibrationFactor) == 0 && Double.compare(_o.lowPassFilter, lowPassFilter) == 0 && doublePower == _o.doublePower && Objects.equals(name, _o.name) && Objects.equals(description, _o.description) && polarity == _o.polarity && type == _o.type && Objects.equals(key, _o.key);
} }
@Override @Override

View File

@ -10,7 +10,6 @@ import com.lanternsoftware.util.dao.annotations.PrimaryKey;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Set;
@DBSerializable(autogen = false) @DBSerializable(autogen = false)
public class BreakerConfig implements IIdentical<BreakerConfig> { public class BreakerConfig implements IIdentical<BreakerConfig> {
@ -203,20 +202,8 @@ public class BreakerConfig implements IIdentical<BreakerConfig> {
return null; return null;
} }
public boolean containsPolarity(Set<String> _groupIds, BreakerPolarity _polarity) {
for (BreakerGroup subGroup : CollectionUtils.makeNotNull(breakerGroups)) {
if (subGroup.containsPolarity(_groupIds, _polarity))
return true;
}
return false;
}
public BillingCurrency getCurrency() { public BillingCurrency getCurrency() {
return CollectionUtils.getFirst(CollectionUtils.transformToSet(CollectionUtils.aggregate(billingPlans, BillingPlan::getRates), BillingRate::getCurrency)); return CollectionUtils.getFirst(CollectionUtils.transformToSet(billingRates, BillingRate::getCurrency));
}
public boolean isMainsPowerTrackedForMeter(int _meter) {
return CollectionUtils.anyQualify(getAllBreakers(), _b->_b.isMain() && (_b.getMeter() == _meter));
} }
@Override @Override

View File

@ -182,20 +182,6 @@ public class BreakerGroup implements IIdentical<BreakerGroup> {
return groups; return groups;
} }
public boolean containsPolarity(Set<String> _groupIds, BreakerPolarity _polarity) {
if ((CollectionUtils.isEmpty(_groupIds) || _groupIds.contains(id)) && CollectionUtils.anyQualify(breakers, _b->_b.getPolarity() == _polarity))
return true;
for (BreakerGroup subGroup : CollectionUtils.makeNotNull(subGroups)) {
if (subGroup.containsPolarity(_groupIds, _polarity))
return true;
}
return false;
}
public boolean isMain() {
return CollectionUtils.anyQualify(breakers, Breaker::isMain);
}
public boolean removeInvalidGroups(Set<Integer> _validPanels) { public boolean removeInvalidGroups(Set<Integer> _validPanels) {
if (subGroups != null) if (subGroups != null)
subGroups.removeIf(_g->!_g.removeInvalidGroups(_validPanels)); subGroups.removeIf(_g->!_g.removeInvalidGroups(_validPanels));

View File

@ -11,8 +11,6 @@ public class BreakerHub implements IIdentical<BreakerHub> {
private int hub; private int hub;
private double voltageCalibrationFactor; private double voltageCalibrationFactor;
private double portCalibrationFactor; private double portCalibrationFactor;
private int phaseCnt;
private int phaseOffsetNs;
private int frequency; private int frequency;
private String bluetoothMac; private String bluetoothMac;
@ -41,31 +39,15 @@ public class BreakerHub implements IIdentical<BreakerHub> {
} }
public double getPortCalibrationFactor() { public double getPortCalibrationFactor() {
return portCalibrationFactor == 0.0?1.20:portCalibrationFactor; return portCalibrationFactor == 0.0?1.25:portCalibrationFactor;
} }
public void setPortCalibrationFactor(double _portCalibrationFactor) { public void setPortCalibrationFactor(double _portCalibrationFactor) {
portCalibrationFactor = _portCalibrationFactor; portCalibrationFactor = _portCalibrationFactor;
} }
public int getPhaseCnt() {
return phaseCnt == 0 ? 2 : phaseCnt;
}
public void setPhaseCnt(int _phaseCnt) {
phaseCnt = _phaseCnt;
}
public int getPhaseOffsetNs() {
return phaseOffsetNs;
}
public void setPhaseOffsetNs(int _phaseOffsetNs) {
phaseOffsetNs = _phaseOffsetNs;
}
public int getFrequency() { public int getFrequency() {
return frequency == 0 ? 60 : frequency; return frequency;
} }
public void setFrequency(int _frequency) { public void setFrequency(int _frequency) {
@ -91,7 +73,7 @@ public class BreakerHub implements IIdentical<BreakerHub> {
@Override @Override
public boolean isIdentical(BreakerHub _o) { public boolean isIdentical(BreakerHub _o) {
if (this == _o) return true; if (this == _o) return true;
return hub == _o.hub && Double.compare(_o.voltageCalibrationFactor, voltageCalibrationFactor) == 0 && Double.compare(_o.portCalibrationFactor, portCalibrationFactor) == 0 && getPhaseCnt() == _o.getPhaseCnt() && getPhaseOffsetNs() == _o.getPhaseOffsetNs() && getFrequency() == _o.getFrequency() && Objects.equals(bluetoothMac, _o.bluetoothMac); return hub == _o.hub && Double.compare(_o.voltageCalibrationFactor, voltageCalibrationFactor) == 0 && Double.compare(_o.portCalibrationFactor, portCalibrationFactor) == 0 && frequency == _o.frequency && Objects.equals(bluetoothMac, _o.bluetoothMac);
} }
@Override @Override

View File

@ -2,7 +2,5 @@ package com.lanternsoftware.datamodel.currentmonitor;
public enum BreakerPolarity { public enum BreakerPolarity {
NORMAL, NORMAL,
SOLAR, SOLAR;
BI_DIRECTIONAL,
BI_DIRECTIONAL_INVERTED
} }

View File

@ -1,52 +0,0 @@
package com.lanternsoftware.datamodel.currentmonitor;
import com.lanternsoftware.util.dao.annotations.DBSerializable;
@DBSerializable
public class EmailCredentials {
private EmailProvider provider;
private String apiKey;
private String apiSecret;
private String emailFrom;
private String serverUrlBase;
public EmailProvider getProvider() {
return provider;
}
public void setProvider(EmailProvider _provider) {
provider = _provider;
}
public String getApiKey() {
return apiKey;
}
public void setApiKey(String _apiKey) {
apiKey = _apiKey;
}
public String getApiSecret() {
return apiSecret;
}
public void setApiSecret(String _apiSecret) {
apiSecret = _apiSecret;
}
public String getEmailFrom() {
return emailFrom;
}
public void setEmailFrom(String _emailFrom) {
emailFrom = _emailFrom;
}
public String getServerUrlBase() {
return serverUrlBase;
}
public void setServerUrlBase(String _serverUrlBase) {
serverUrlBase = _serverUrlBase;
}
}

View File

@ -1,6 +0,0 @@
package com.lanternsoftware.datamodel.currentmonitor;
public enum EmailProvider {
SENDGRID,
MAILJET
}

View File

@ -8,6 +8,7 @@ import com.lanternsoftware.util.dao.annotations.DBSerializable;
import com.lanternsoftware.util.mutable.MutableDouble; import com.lanternsoftware.util.mutable.MutableDouble;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator; import java.util.Comparator;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
@ -25,7 +26,6 @@ public class EnergySummary {
private EnergyViewMode viewMode; private EnergyViewMode viewMode;
private Date start; private Date start;
private List<EnergySummary> subGroups; private List<EnergySummary> subGroups;
private boolean main;
private float[] energy; private float[] energy;
private float[] gridEnergy; private float[] gridEnergy;
private double peakToGrid; private double peakToGrid;
@ -40,7 +40,6 @@ public class EnergySummary {
public EnergySummary(BreakerGroup _group, List<HubPowerMinute> _power, EnergyViewMode _viewMode, Date _start, TimeZone _timezone) { public EnergySummary(BreakerGroup _group, List<HubPowerMinute> _power, EnergyViewMode _viewMode, Date _start, TimeZone _timezone) {
groupId = _group.getId(); groupId = _group.getId();
groupName = _group.getName(); groupName = _group.getName();
main = _group.isMain();
viewMode = _viewMode; viewMode = _viewMode;
start = _start; start = _start;
accountId = _group.getAccountId(); accountId = _group.getAccountId();
@ -51,30 +50,29 @@ public class EnergySummary {
} }
public void addEnergy(BreakerGroup _group, List<HubPowerMinute> _hubPower) { public void addEnergy(BreakerGroup _group, List<HubPowerMinute> _hubPower) {
Map<Integer, Breaker> breakers = CollectionUtils.transformToMap(_group.getAllBreakers(), Breaker::getIntKey); Map<String, Breaker> breakers = CollectionUtils.transformToMap(_group.getAllBreakers(), Breaker::getKey);
Map<Integer, BreakerGroup> breakerKeyToGroup = new HashMap<>(); Map<String, BreakerGroup> breakerKeyToGroup = new HashMap<>();
for (BreakerGroup group : _group.getAllBreakerGroups()) { for (BreakerGroup group : _group.getAllBreakerGroups()) {
for (Breaker b : CollectionUtils.makeNotNull(group.getBreakers())) { for (Breaker b : CollectionUtils.makeNotNull(group.getBreakers())) {
breakerKeyToGroup.put(b.getIntKey(), group); breakerKeyToGroup.put(b.getKey(), group);
} }
} }
addEnergy(breakers, breakerKeyToGroup, _hubPower); addEnergy(breakers, breakerKeyToGroup, _hubPower);
} }
public void addEnergy(Map<Integer, Breaker> _breakers, Map<Integer, BreakerGroup> _breakerKeyToGroup, List<HubPowerMinute> _hubPower) { public void addEnergy(Map<String, Breaker> _breakers, Map<String, BreakerGroup> _breakerKeyToGroup, List<HubPowerMinute> _hubPower) {
if (CollectionUtils.isEmpty(_hubPower) || CollectionUtils.anyQualify(_hubPower, _p -> _p.getAccountId() != accountId)) if (CollectionUtils.isEmpty(_hubPower) || CollectionUtils.anyQualify(_hubPower, _p -> _p.getAccountId() != accountId))
return; return;
_hubPower.sort(Comparator.comparing(HubPowerMinute::getMinute)); _hubPower.sort(Comparator.comparing(HubPowerMinute::getMinute));
for (Date minute : CollectionUtils.transformToSet(_hubPower, HubPowerMinute::getMinuteAsDate)) { for (Date minute : CollectionUtils.transformToSet(_hubPower, HubPowerMinute::getMinuteAsDate)) {
resetEnergy(minute); resetEnergy(minute);
} }
Set<Integer> meterMainsTracked = CollectionUtils.transformToSet(CollectionUtils.filter(_breakers.values(), Breaker::isMain), Breaker::getMeter);
int idx; int idx;
Map<Integer, Map<Integer, MeterMinute>> minutes = new HashMap<>(); Map<Integer, Map<Integer, MeterMinute>> minutes = new HashMap<>();
for (HubPowerMinute hubPower : _hubPower) { for (HubPowerMinute hubPower : _hubPower) {
Date minute = hubPower.getMinuteAsDate(); Date minute = hubPower.getMinuteAsDate();
for (BreakerPowerMinute breaker : CollectionUtils.makeNotNull(hubPower.getBreakers())) { for (BreakerPowerMinute breaker : CollectionUtils.makeNotNull(hubPower.getBreakers())) {
int key = breaker.breakerIntKey(); String key = breaker.breakerKey();
Breaker b = _breakers.get(key); Breaker b = _breakers.get(key);
if (b == null) if (b == null)
continue; continue;
@ -86,12 +84,10 @@ public class EnergySummary {
for (Float power : CollectionUtils.makeNotNull(breaker.getReadings())) { for (Float power : CollectionUtils.makeNotNull(breaker.getReadings())) {
if (idx >= 60) if (idx >= 60)
break; break;
if (!meterMainsTracked.contains(b.getMeter()) || b.isMain()) { if (power > 0)
if (power > 0) meter.usage[idx] += power;
meter.usage[idx] += power; else
else meter.solar[idx] -= power;
meter.solar[idx] -= power;
}
addEnergy(group.getId(), minute, power); addEnergy(group.getId(), minute, power);
idx++; idx++;
} }
@ -129,7 +125,7 @@ public class EnergySummary {
for (HubPowerMinute hubPower : _hubPower) { for (HubPowerMinute hubPower : _hubPower) {
Date minute = hubPower.getMinuteAsDate(); Date minute = hubPower.getMinuteAsDate();
for (BreakerPowerMinute breaker : CollectionUtils.makeNotNull(hubPower.getBreakers())) { for (BreakerPowerMinute breaker : CollectionUtils.makeNotNull(hubPower.getBreakers())) {
int key = breaker.breakerIntKey(); String key = breaker.breakerKey();
Breaker b = _breakers.get(key); Breaker b = _breakers.get(key);
if (b == null) if (b == null)
continue; continue;
@ -140,9 +136,9 @@ public class EnergySummary {
idx = 0; idx = 0;
double flow = 0.0; double flow = 0.0;
for (Float power : CollectionUtils.makeNotNull(breaker.getReadings())) { for (Float power : CollectionUtils.makeNotNull(breaker.getReadings())) {
if (power < 0 && (meter.flow[idx] < 0.0)) if ((b.getPolarity() == BreakerPolarity.SOLAR) && (meter.flow[idx] < 0.0))
flow -= meter.flow[idx] * (power / meter.solar[idx]); flow -= meter.flow[idx] * (power / meter.solar[idx]);
else if (power > 0 && (meter.flow[idx] > 0.0)) else if ((b.getPolarity() != BreakerPolarity.SOLAR) && (meter.flow[idx] > 0.0))
flow += meter.flow[idx] * (power / meter.usage[idx]); flow += meter.flow[idx] * (power / meter.usage[idx]);
idx++; idx++;
} }
@ -152,11 +148,11 @@ public class EnergySummary {
} }
public void resetEnergy(Date _readTime) { public void resetEnergy(Date _readTime) {
if (energy != null) { if (energy == null)
int idx = viewMode.blockIndex(start, _readTime, timezone); return;
if (idx < energy.length) int idx = viewMode.blockIndex(start, _readTime, timezone);
energy[idx] = 0f; if (idx < energy.length)
} energy[idx] = 0f;
for (EnergySummary subGroup : CollectionUtils.makeNotNull(subGroups)) { for (EnergySummary subGroup : CollectionUtils.makeNotNull(subGroups)) {
subGroup.resetEnergy(_readTime); subGroup.resetEnergy(_readTime);
} }
@ -292,14 +288,6 @@ public class EnergySummary {
subGroups = _subGroups; subGroups = _subGroups;
} }
public boolean isMain() {
return main;
}
public void setMain(boolean _main) {
main = _main;
}
public float[] getEnergy() { public float[] getEnergy() {
return energy; return energy;
} }
@ -374,7 +362,7 @@ public class EnergySummary {
public double joules(Set<String> _selectedBreakers, boolean _includeSubgroups, GridFlow _mode) { public double joules(Set<String> _selectedBreakers, boolean _includeSubgroups, GridFlow _mode) {
double joules = 0.0; double joules = 0.0;
if (_includeSubgroups && !isMain()) { if (_includeSubgroups) {
for (EnergySummary group : CollectionUtils.makeNotNull(subGroups)) { for (EnergySummary group : CollectionUtils.makeNotNull(subGroups)) {
joules += group.joules(_selectedBreakers, true, _mode); joules += group.joules(_selectedBreakers, true, _mode);
} }

View File

@ -21,7 +21,7 @@ public enum HubConfigCharacteristic {
Shutdown(13, CharacteristicFlag.WRITE), Shutdown(13, CharacteristicFlag.WRITE),
Version(14, CharacteristicFlag.READ), Version(14, CharacteristicFlag.READ),
Update(15, CharacteristicFlag.WRITE), Update(15, CharacteristicFlag.WRITE),
ReloadConfig(16, CharacteristicFlag.WRITE); ReloadConfig(15, CharacteristicFlag.WRITE);
public final int idx; public final int idx;
public final UUID uuid; public final UUID uuid;

View File

@ -8,7 +8,7 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
public abstract class HubConfigService { public class HubConfigService {
public static final UUIDFormatter uuidFormat = new UUIDFormatter("c5650001-d50f-49af-b906-cada0dc17937"); public static final UUIDFormatter uuidFormat = new UUIDFormatter("c5650001-d50f-49af-b906-cada0dc17937");
private static final AESTool aes = new AESTool(37320708309265127L,-8068168662055796771L,-4867793276337148572L,4425609941731230765L); private static final AESTool aes = new AESTool(37320708309265127L,-8068168662055796771L,-4867793276337148572L,4425609941731230765L);
private static final UUID serviceUUID = uuidFormat.format(1); private static final UUID serviceUUID = uuidFormat.format(1);
@ -20,7 +20,7 @@ public abstract class HubConfigService {
return serviceUUID; return serviceUUID;
} }
public static List<HubConfigCharacteristic> getCharacteristics() { public List<HubConfigCharacteristic> getCharacteristics() {
return Arrays.asList(HubConfigCharacteristic.values()); return Arrays.asList(HubConfigCharacteristic.values());
} }

View File

@ -36,10 +36,6 @@ public class NetworkStatus {
pingSuccessful = _pingSuccessful; pingSuccessful = _pingSuccessful;
} }
public boolean isNetworkConnected() {
return isWifiConnected() || isEthernetConnected();
}
public boolean isWifiConnected() { public boolean isWifiConnected() {
return CollectionUtils.isNotEmpty(wifiIPs); return CollectionUtils.isNotEmpty(wifiIPs);
} }

View File

@ -15,45 +15,59 @@ import java.util.concurrent.atomic.AtomicInteger;
public class BOM { public class BOM {
List<LineItem> lineItems; List<LineItem> lineItems;
private static final Map<Integer, String> ctSizes = new TreeMap<>();
static {
ctSizes.put(15, "https://store.lanternpowermonitor.com/product/15a-yhdc-current-transformer/3");
ctSizes.put(20, "https://store.lanternpowermonitor.com/product/20a-yhdc-current-transformer/4");
ctSizes.put(30, "https://store.lanternpowermonitor.com/product/30a-yhdc-current-transformer/5");
ctSizes.put(50, "https://store.lanternpowermonitor.com/product/50a-yhdc-current-transformer/6");
ctSizes.put(60, "https://store.lanternpowermonitor.com/product/60a-yhdc-current-transformer/7");
ctSizes.put(100, "https://store.lanternpowermonitor.com/product/100a-yhdc-current-transformer/8");
}
public static BOM fromConfig(BreakerConfig _config) { public static BOM fromConfig(BreakerConfig _config) {
BOM bom = new BOM(); BOM bom = new BOM();
bom.setLineItems(new ArrayList<>()); bom.setLineItems(new ArrayList<>());
Map<Integer, AtomicInteger> ctCnts = new TreeMap<>(); Map<Integer, AtomicInteger> ctCnts = new TreeMap<>();
Map<Integer, Breaker> breakers = CollectionUtils.transformToMap(_config.getAllBreakers(), Breaker::getIntKey); Map<Integer, AtomicInteger> ctDuplicates = new TreeMap<>();
for (Breaker breaker : breakers.values()) { for (Breaker breaker : CollectionUtils.makeNotNull(_config.getAllBreakers())) {
if (bom.isUntrackedBottom(breakers, breaker)) if (breaker.getSizeAmps() <= 20) {
continue; ctCnts.computeIfAbsent(20, (_k) -> new AtomicInteger(0)).getAndIncrement();
for (int size : ctSizes.keySet()) { if (breaker.getType() == BreakerType.DOUBLE_POLE_TOP_ONE_CT)
if (breaker.getSizeAmps() <= size) { ctDuplicates.computeIfAbsent(20, (_k) -> new AtomicInteger(0)).getAndIncrement();
ctCnts.computeIfAbsent(size, (_k) -> new AtomicInteger(0)).getAndIncrement();
break;
}
} }
else if (breaker.getSizeAmps() <= 30) {
ctCnts.computeIfAbsent(30, (_k) -> new AtomicInteger(0)).getAndIncrement();
if (breaker.getType() == BreakerType.DOUBLE_POLE_TOP_ONE_CT)
ctDuplicates.computeIfAbsent(30, (_k) -> new AtomicInteger(0)).getAndIncrement();
}
else {
ctCnts.computeIfAbsent(50, (_k) -> new AtomicInteger(0)).getAndIncrement();
if (breaker.getType() == BreakerType.DOUBLE_POLE_TOP_ONE_CT)
ctDuplicates.computeIfAbsent(50, (_k) -> new AtomicInteger(0)).getAndIncrement();
}
}
for (Map.Entry<Integer, AtomicInteger> ctCnt : ctDuplicates.entrySet()) {
AtomicInteger cnt = ctCnts.get(ctCnt.getKey());
if (cnt != null)
cnt.getAndAdd(-ctCnt.getValue().get());
} }
int breakerCnt = CollectionUtils.sumIntegers(CollectionUtils.transform(ctCnts.values(), AtomicInteger::get)); int breakerCnt = CollectionUtils.sumIntegers(CollectionUtils.transform(ctCnts.values(), AtomicInteger::get));
int hubCnt = (int)Math.ceil(breakerCnt/15.0); int hubCnt = (int)Math.ceil(breakerCnt/15.0);
bom.getLineItems().add(new LineItem("Lantern Power Monitor Case", "LPMC1", "https://github.com/MarkBryanMilligan/LanternPowerMonitor/tree/main/case", 0.10, 3.00, hubCnt)); bom.getLineItems().add(new LineItem("Lantern Power Monitor Case", "LPMC1", "https://github.com/MarkBryanMilligan/LanternPowerMonitor/tree/main/case", 0.10, 3.00, hubCnt));
bom.getLineItems().add(new LineItem("Lantern Power Monitor Case Lid", "LPMCL1", "https://github.com/MarkBryanMilligan/LanternPowerMonitor/tree/main/case", 0.10, 2.00, hubCnt)); bom.getLineItems().add(new LineItem("Lantern Power Monitor Case Lid", "LPMCL1", "https://github.com/MarkBryanMilligan/LanternPowerMonitor/tree/main/case", 0.10, 2.00, hubCnt));
bom.getLineItems().add(new LineItem("Lantern Power Monitor PCB", "LPMPCB1", "https://store.lanternpowermonitor.com/product/assembled-lantern-power-monitor-pcb/1", 1.00, 5.00, hubCnt)); bom.getLineItems().add(new LineItem("Lantern Power Monitor Soldering Jig", "LPMSJ1", "https://github.com/MarkBryanMilligan/LanternPowerMonitor/tree/main/case", 0.10, 4.00, 1));
bom.getLineItems().add(new LineItem("Lantern Power Monitor PCB", "LPMPCB1", "https://github.com/MarkBryanMilligan/LanternPowerMonitor/tree/main/pcb", 1.00, 5.00, hubCnt));
bom.getLineItems().add(new LineItem("Raspberry Pi 3 Model A+", "3A+", "https://www.raspberrypi.org/products/raspberry-pi-3-model-a-plus/", 25.0, 35.0, hubCnt)); bom.getLineItems().add(new LineItem("Raspberry Pi 3 Model A+", "3A+", "https://www.raspberrypi.org/products/raspberry-pi-3-model-a-plus/", 25.0, 35.0, hubCnt));
bom.getLineItems().add(new LineItem("Jameco 12V AC/AC Adapter", "10428", "https://store.lanternpowermonitor.com/product/120vac-to-12vac-voltage-transformer/2", 10.95, 15.00, hubCnt)); bom.getLineItems().add(new LineItem("Jameco 12V AC/AC Adapter", "10428", "https://www.jameco.com/z/ACU120100Z9121-Jameco-Reliapro-AC-to-AC-Wall-Adapter-Transformer-12-Volt-AC-1000mA-Black-Straight-3-5mm-Male-Plug_10428.html", 10.95, 15.00, hubCnt));
bom.getLineItems().add(new LineItem("8gb Sandisk Industrial memory card", "SDSDQAF3-008G-I", "https://www.amazon.com/gp/product/B07BZ5SY18", 4.00, 5.00, hubCnt)); bom.getLineItems().add(new LineItem("16gb memory card", "P-SDU16GU185GW-GE", "https://www.microcenter.com/product/486146/micro-center-16gb-microsdhc-class-10-flash-memory-card", 4.00, 5.00, hubCnt));
bom.getLineItems().add(new LineItem("40-pin GPIO header", "C169819", "https://lcsc.com/product-detail/Pin-Header-Female-Header_Ckmtw-Shenzhen-Cankemeng-C169819_C169819.html", 0.36, 0.80, hubCnt));
bom.getLineItems().add(new LineItem("MCP3008", "MCP3008-I-P", "https://www.digikey.com/en/products/detail/microchip-technology/MCP3008-I-P/319422", 2.41, 4.00, hubCnt*2));
bom.getLineItems().add(new LineItem("10uF 25V 4*5 Capacitor", "C43846", "https://lcsc.com/product-detail/Aluminum-Electrolytic-Capacitors-Leaded_CX-Dongguan-Chengxing-Elec-10uF-25V-4-5_C43846.html", 0.01, 0.10, hubCnt));
bom.getLineItems().add(new LineItem("22uF 25V 4*7 Capacitor", "C43840", "https://lcsc.com/product-detail/Aluminum-Electrolytic-Capacitors-Leaded_CX-Dongguan-Chengxing-Elec-22uF-25V-4-7_C43840.html", 0.01, 0.10, hubCnt));
bom.getLineItems().add(new LineItem("10KΩ Resistor", "C385441", "https://lcsc.com/product-detail/Metal-Film-Resistor-TH_TyoHM-RN1-2WS10K%CE%A9FT-BA1_C385441.html", 0.01, 0.10, hubCnt*2));
bom.getLineItems().add(new LineItem("12KΩ Resistor", "C385449", "https://lcsc.com/product-detail/Metal-Film-Resistor-TH_TyoHM-RN1-2WS12K%CE%A9FT-BA1_C385449.html", 0.01, 0.10, hubCnt));
bom.getLineItems().add(new LineItem("180KΩ Resistor", "C385460", "https://lcsc.com/product-detail/Metal-Film-Resistor-TH_TyoHM-RN1-2WS180K%CE%A9FT-BA1_C385460.html", 0.01, 0.10, hubCnt));
bom.getLineItems().add(new LineItem("33KΩ Resistor", "C385498", "https://lcsc.com/product-detail/Metal-Film-Resistor-TH_TyoHM-RN1-2WS33K%CE%A9FT-BA1_C385498.html", 0.01, 0.10, hubCnt));
bom.getLineItems().add(new LineItem("68KΩ Resistor", "C385541", "https://lcsc.com/product-detail/Metal-Film-Resistor-TH_TyoHM-RN1-2WS68K%CE%A9FT-BA1_C385541.html", 0.01, 0.10, hubCnt));
bom.getLineItems().add(new LineItem("3.5mm Headphone Jack", "PJ-3583-B", "https://lcsc.com/product-detail/Audio-Video-Connectors_XKB-Enterprise-PJ-3583-B_C397337.html", 0.16, 0.25, hubCnt*16));
bom.getLineItems().add(new LineItem("M2.5x10mm Cap Screw", "A15120300ux0225", "https://www.amazon.com/gp/product/B01B1OD7IK", 0.10, 0.20, hubCnt*8)); bom.getLineItems().add(new LineItem("M2.5x10mm Cap Screw", "A15120300ux0225", "https://www.amazon.com/gp/product/B01B1OD7IK", 0.10, 0.20, hubCnt*8));
bom.getLineItems().add(new LineItem("M2.5x11mm Female x Female Standoff", "", "https://www.ebay.com/itm/50pcs-M2-5-Female-Hex-Screw-Brass-PCB-Standoffs-Hexagonal-Spacers/172746413434", 0.15, 0.25, hubCnt*4)); bom.getLineItems().add(new LineItem("M2.5x11mm Female x Female Standoff", "", "https://www.ebay.com/itm/50pcs-M2-5-Female-Hex-Screw-Brass-PCB-Standoffs-Hexagonal-Spacers/172746413434", 0.15, 0.25, hubCnt*4));
bom.getLineItems().add(new LineItem("M2.5x12mm Female x Male Standoff", "", "https://www.ebay.com/itm/M2-5-2-5mm-Thread-6mm-Brass-Standoff-Spacer-Male-x-Female-20-50pcs-New/283432513974", 0.15, 0.25, hubCnt*4)); bom.getLineItems().add(new LineItem("M2.5x12mm Female x Male Standoff", "", "https://www.ebay.com/itm/M2-5-2-5mm-Thread-6mm-Brass-Standoff-Spacer-Male-x-Female-20-50pcs-New/283432513974", 0.15, 0.25, hubCnt*4));
for (Map.Entry<Integer, AtomicInteger> ctCnt : ctCnts.entrySet()) { for (Map.Entry<Integer, AtomicInteger> ctCnt : ctCnts.entrySet()) {
bom.getLineItems().add(new LineItem(String.format("%d Amp Current Transformer", ctCnt.getKey()), String.format("SCT-013-%03d", ctCnt.getKey()), ctSizes.get(ctCnt.getKey()), 5.00, 6.00, ctCnt.getValue().get())); bom.getLineItems().add(new LineItem(String.format("%d Amp Current Transformer", ctCnt.getKey()), String.format("SCT-013-0%d", ctCnt.getKey()), "N/A", 5.00, 7.00, ctCnt.getValue().get()));
} }
return bom; return bom;
} }
@ -79,11 +93,4 @@ public class BOM {
rows.add(CollectionUtils.asArrayList("Total", "", "", "", "", "", String.format("$%.2f", selfCost), String.format("$%.2f", shippedCost))); rows.add(CollectionUtils.asArrayList("Total", "", "", "", "", "", String.format("$%.2f", selfCost), String.format("$%.2f", shippedCost)));
return new CSV(headers, rows, headers.size()); return new CSV(headers, rows, headers.size());
} }
private boolean isUntrackedBottom(Map<Integer, Breaker> _breakers, Breaker _breaker) {
if (_breaker.getType() != BreakerType.DOUBLE_POLE_BOTTOM)
return false;
Breaker topBreaker = _breakers.get(Breaker.intKey(_breaker.getPanel(), _breaker.getSpaceIndex() - 2));
return topBreaker != null && topBreaker.getType() == BreakerType.DOUBLE_POLE_TOP_ONE_CT;
}
} }

View File

@ -28,8 +28,6 @@ public class BreakerHubSerializer extends AbstractDaoSerializer<BreakerHub>
d.put("hub", _o.getHub()); d.put("hub", _o.getHub());
d.put("voltage_calibration_factor", _o.getRawVoltageCalibrationFactor()); d.put("voltage_calibration_factor", _o.getRawVoltageCalibrationFactor());
d.put("port_calibration_factor", _o.getRawPortCalibrationFactor()); d.put("port_calibration_factor", _o.getRawPortCalibrationFactor());
d.put("phase_cnt", _o.getPhaseCnt());
d.put("phase_offset_ns", _o.getPhaseOffsetNs());
d.put("frequency", _o.getFrequency()); d.put("frequency", _o.getFrequency());
d.put("bluetooth_mac", _o.getBluetoothMac()); d.put("bluetooth_mac", _o.getBluetoothMac());
return d; return d;
@ -42,8 +40,6 @@ public class BreakerHubSerializer extends AbstractDaoSerializer<BreakerHub>
o.setHub(DaoSerializer.getInteger(_d, "hub")); o.setHub(DaoSerializer.getInteger(_d, "hub"));
o.setVoltageCalibrationFactor(DaoSerializer.getDouble(_d, "voltage_calibration_factor")); o.setVoltageCalibrationFactor(DaoSerializer.getDouble(_d, "voltage_calibration_factor"));
o.setPortCalibrationFactor(DaoSerializer.getDouble(_d, "port_calibration_factor")); o.setPortCalibrationFactor(DaoSerializer.getDouble(_d, "port_calibration_factor"));
o.setPhaseCnt(DaoSerializer.getInteger(_d, "phase_cnt"));
o.setPhaseOffsetNs(DaoSerializer.getInteger(_d, "phase_offset_ns"));
o.setFrequency(DaoSerializer.getInteger(_d, "frequency")); o.setFrequency(DaoSerializer.getInteger(_d, "frequency"));
o.setBluetoothMac(DaoSerializer.getString(_d, "bluetooth_mac")); o.setBluetoothMac(DaoSerializer.getString(_d, "bluetooth_mac"));
return o; return o;

View File

@ -35,13 +35,11 @@ public class BreakerSerializer extends AbstractDaoSerializer<Breaker>
d.put("name", _o.getName()); d.put("name", _o.getName());
d.put("description", _o.getDescription()); d.put("description", _o.getDescription());
d.put("size_amps", _o.getSizeAmps()); d.put("size_amps", _o.getSizeAmps());
d.put("phase_offset_ns", _o.getPhaseOffsetNs());
d.put("calibration_factor", _o.getCalibrationFactor()); d.put("calibration_factor", _o.getCalibrationFactor());
d.put("low_pass_filter", _o.getLowPassFilter()); d.put("low_pass_filter", _o.getLowPassFilter());
d.put("polarity", DaoSerializer.toEnumName(_o.getPolarity())); d.put("polarity", DaoSerializer.toEnumName(_o.getPolarity()));
d.put("double_power", _o.isDoublePower()); d.put("double_power", _o.isDoublePower());
d.put("type", DaoSerializer.toEnumName(_o.getType())); d.put("type", DaoSerializer.toEnumName(_o.getType()));
d.put("main", _o.isMain());
return d; return d;
} }
@ -57,13 +55,11 @@ public class BreakerSerializer extends AbstractDaoSerializer<Breaker>
o.setName(DaoSerializer.getString(_d, "name")); o.setName(DaoSerializer.getString(_d, "name"));
o.setDescription(DaoSerializer.getString(_d, "description")); o.setDescription(DaoSerializer.getString(_d, "description"));
o.setSizeAmps(DaoSerializer.getInteger(_d, "size_amps")); o.setSizeAmps(DaoSerializer.getInteger(_d, "size_amps"));
o.setPhaseOffsetNs(DaoSerializer.getInteger(_d, "phase_offset_ns"));
o.setCalibrationFactor(DaoSerializer.getDouble(_d, "calibration_factor")); o.setCalibrationFactor(DaoSerializer.getDouble(_d, "calibration_factor"));
o.setLowPassFilter(DaoSerializer.getDouble(_d, "low_pass_filter")); o.setLowPassFilter(DaoSerializer.getDouble(_d, "low_pass_filter"));
o.setPolarity(DaoSerializer.getEnum(_d, "polarity", BreakerPolarity.class)); o.setPolarity(DaoSerializer.getEnum(_d, "polarity", BreakerPolarity.class));
o.setDoublePower(DaoSerializer.getBoolean(_d, "double_power")); o.setDoublePower(DaoSerializer.getBoolean(_d, "double_power"));
o.setType(DaoSerializer.getEnum(_d, "type", BreakerType.class)); o.setType(DaoSerializer.getEnum(_d, "type", BreakerType.class));
o.setMain(DaoSerializer.getBoolean(_d, "main"));
return o; return o;
} }
} }

View File

@ -1,48 +0,0 @@
package com.lanternsoftware.datamodel.currentmonitor.dao;
import com.lanternsoftware.datamodel.currentmonitor.EmailCredentials;
import com.lanternsoftware.datamodel.currentmonitor.EmailProvider;
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 EmailCredentialsSerializer extends AbstractDaoSerializer<EmailCredentials>
{
@Override
public Class<EmailCredentials> getSupportedClass()
{
return EmailCredentials.class;
}
@Override
public List<DaoProxyType> getSupportedProxies() {
return Collections.singletonList(DaoProxyType.MONGO);
}
@Override
public DaoEntity toDaoEntity(EmailCredentials _o)
{
DaoEntity d = new DaoEntity();
d.put("provider", DaoSerializer.toEnumName(_o.getProvider()));
d.put("api_key", _o.getApiKey());
d.put("api_secret", _o.getApiSecret());
d.put("email_from", _o.getEmailFrom());
d.put("server_url_base", _o.getServerUrlBase());
return d;
}
@Override
public EmailCredentials fromDaoEntity(DaoEntity _d)
{
EmailCredentials o = new EmailCredentials();
o.setProvider(DaoSerializer.getEnum(_d, "provider", EmailProvider.class));
o.setApiKey(DaoSerializer.getString(_d, "api_key"));
o.setApiSecret(DaoSerializer.getString(_d, "api_secret"));
o.setEmailFrom(DaoSerializer.getString(_d, "email_from"));
o.setServerUrlBase(DaoSerializer.getString(_d, "server_url_base"));
return o;
}
}

View File

@ -9,6 +9,7 @@ import com.lanternsoftware.util.dao.DaoEntity;
import com.lanternsoftware.util.dao.DaoProxyType; import com.lanternsoftware.util.dao.DaoProxyType;
import com.lanternsoftware.util.dao.DaoSerializer; import com.lanternsoftware.util.dao.DaoSerializer;
import java.nio.ByteBuffer;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.TimeZone; import java.util.TimeZone;
@ -37,7 +38,6 @@ public class EnergySummarySerializer extends AbstractDaoSerializer<EnergySummary
d.put("view_mode", DaoSerializer.toEnumName(_o.getViewMode())); d.put("view_mode", DaoSerializer.toEnumName(_o.getViewMode()));
d.put("start", DaoSerializer.toLong(_o.getStart())); d.put("start", DaoSerializer.toLong(_o.getStart()));
d.put("sub_groups", DaoSerializer.toDaoEntities(_o.getSubGroups(), DaoProxyType.MONGO)); d.put("sub_groups", DaoSerializer.toDaoEntities(_o.getSubGroups(), DaoProxyType.MONGO));
d.put("main", _o.isMain());
TimeZone tz = DateUtils.defaultTimeZone(_o.getTimeZone()); TimeZone tz = DateUtils.defaultTimeZone(_o.getTimeZone());
d.put("timezone", tz.getID()); d.put("timezone", tz.getID());
if (_o.getEnergy() != null) if (_o.getEnergy() != null)
@ -61,7 +61,6 @@ public class EnergySummarySerializer extends AbstractDaoSerializer<EnergySummary
o.setViewMode(DaoSerializer.getEnum(_d, "view_mode", EnergyViewMode.class)); o.setViewMode(DaoSerializer.getEnum(_d, "view_mode", EnergyViewMode.class));
o.setStart(DaoSerializer.getDate(_d, "start")); o.setStart(DaoSerializer.getDate(_d, "start"));
o.setSubGroups(DaoSerializer.getList(_d, "sub_groups", EnergySummary.class)); o.setSubGroups(DaoSerializer.getList(_d, "sub_groups", EnergySummary.class));
o.setMain(DaoSerializer.getBoolean(_d, "main"));
o.setTimeZone(DateUtils.fromTimeZoneId(DaoSerializer.getString(_d, "timezone"))); o.setTimeZone(DateUtils.fromTimeZoneId(DaoSerializer.getString(_d, "timezone")));
o.setEnergy(CollectionUtils.toFloatArray(DaoSerializer.getByteArray(_d, "energy"))); o.setEnergy(CollectionUtils.toFloatArray(DaoSerializer.getByteArray(_d, "energy")));
o.setGridEnergy(CollectionUtils.toFloatArray(DaoSerializer.getByteArray(_d, "grid_energy"))); o.setGridEnergy(CollectionUtils.toFloatArray(DaoSerializer.getByteArray(_d, "grid_energy")));

View File

@ -1,41 +0,0 @@
package com.lanternsoftware.datamodel.currentmonitor.hub;
import com.lanternsoftware.datamodel.currentmonitor.Breaker;
import com.lanternsoftware.util.dao.annotations.DBSerializable;
import java.util.List;
@DBSerializable
public class BreakerSample {
private int panel;
private int space;
private List<PowerSample> samples;
public int key() {
return Breaker.intKey(panel, space);
}
public int getPanel() {
return panel;
}
public void setPanel(int _panel) {
panel = _panel;
}
public int getSpace() {
return space;
}
public void setSpace(int _space) {
space = _space;
}
public List<PowerSample> getSamples() {
return samples;
}
public void setSamples(List<PowerSample> _samples) {
samples = _samples;
}
}

View File

@ -1,42 +0,0 @@
package com.lanternsoftware.datamodel.currentmonitor.hub;
import com.lanternsoftware.util.DateUtils;
import com.lanternsoftware.util.dao.annotations.DBSerializable;
import java.util.Date;
import java.util.List;
@DBSerializable(autogen = false)
public class HubSample {
private int accountId;
private Date sampleDate;
private List<BreakerSample> breakers;
public String getId() {
return String.format("%d-%d", accountId, DateUtils.toLong(sampleDate));
}
public int getAccountId() {
return accountId;
}
public void setAccountId(int _accountId) {
accountId = _accountId;
}
public Date getSampleDate() {
return sampleDate;
}
public void setSampleDate(Date _sampleDate) {
sampleDate = _sampleDate;
}
public List<BreakerSample> getBreakers() {
return breakers;
}
public void setBreakers(List<BreakerSample> _breakers) {
breakers = _breakers;
}
}

View File

@ -1,43 +0,0 @@
package com.lanternsoftware.datamodel.currentmonitor.hub;
import com.lanternsoftware.util.dao.annotations.DBSerializable;
@DBSerializable
public class PowerSample {
public long nanoTime;
public int cycle;
public double voltage;
public double current;
public long getNanoTime() {
return nanoTime;
}
public void setNanoTime(long _nanoTime) {
nanoTime = _nanoTime;
}
public int getCycle() {
return cycle;
}
public void setCycle(int _cycle) {
cycle = _cycle;
}
public double getVoltage() {
return voltage;
}
public void setVoltage(double _voltage) {
voltage = _voltage;
}
public double getCurrent() {
return current;
}
public void setCurrent(double _current) {
current = _current;
}
}

View File

@ -1,44 +0,0 @@
package com.lanternsoftware.datamodel.currentmonitor.hub.dao;
import com.lanternsoftware.datamodel.currentmonitor.hub.BreakerSample;
import com.lanternsoftware.datamodel.currentmonitor.hub.PowerSample;
import com.lanternsoftware.util.dao.AbstractDaoSerializer;
import com.lanternsoftware.util.dao.DaoEntity;
import com.lanternsoftware.util.dao.DaoProxyType;
import com.lanternsoftware.util.dao.DaoSerializer;
import java.util.Collections;
import java.util.List;
public class BreakerSampleSerializer extends AbstractDaoSerializer<BreakerSample>
{
@Override
public Class<BreakerSample> getSupportedClass()
{
return BreakerSample.class;
}
@Override
public List<DaoProxyType> getSupportedProxies() {
return Collections.singletonList(DaoProxyType.MONGO);
}
@Override
public DaoEntity toDaoEntity(BreakerSample _o)
{
DaoEntity d = new DaoEntity();
d.put("panel", _o.getPanel());
d.put("space", _o.getSpace());
d.put("samples", DaoSerializer.toDaoEntities(_o.getSamples(), DaoProxyType.MONGO));
return d;
}
@Override
public BreakerSample fromDaoEntity(DaoEntity _d)
{
BreakerSample o = new BreakerSample();
o.setPanel(DaoSerializer.getInteger(_d, "panel"));
o.setSpace(DaoSerializer.getInteger(_d, "space"));
o.setSamples(DaoSerializer.getList(_d, "samples", PowerSample.class));
return o;
}
}

View File

@ -1,45 +0,0 @@
package com.lanternsoftware.datamodel.currentmonitor.hub.dao;
import com.lanternsoftware.datamodel.currentmonitor.hub.BreakerSample;
import com.lanternsoftware.datamodel.currentmonitor.hub.HubSample;
import com.lanternsoftware.util.dao.AbstractDaoSerializer;
import com.lanternsoftware.util.dao.DaoEntity;
import com.lanternsoftware.util.dao.DaoProxyType;
import com.lanternsoftware.util.dao.DaoSerializer;
import java.util.Collections;
import java.util.List;
public class HubSampleSerializer extends AbstractDaoSerializer<HubSample>
{
@Override
public Class<HubSample> getSupportedClass()
{
return HubSample.class;
}
@Override
public List<DaoProxyType> getSupportedProxies() {
return Collections.singletonList(DaoProxyType.MONGO);
}
@Override
public DaoEntity toDaoEntity(HubSample _o)
{
DaoEntity d = new DaoEntity();
d.put("_id", _o.getId());
d.put("account_id", _o.getAccountId());
d.put("sample_date", DaoSerializer.toLong(_o.getSampleDate()));
d.put("breakers", DaoSerializer.toDaoEntities(_o.getBreakers(), DaoProxyType.MONGO));
return d;
}
@Override
public HubSample fromDaoEntity(DaoEntity _d)
{
HubSample o = new HubSample();
o.setAccountId(DaoSerializer.getInteger(_d, "account_id"));
o.setSampleDate(DaoSerializer.getDate(_d, "sample_date"));
o.setBreakers(DaoSerializer.getList(_d, "breakers", BreakerSample.class));
return o;
}
}

View File

@ -1,45 +0,0 @@
package com.lanternsoftware.datamodel.currentmonitor.hub.dao;
import com.lanternsoftware.datamodel.currentmonitor.hub.PowerSample;
import com.lanternsoftware.util.dao.AbstractDaoSerializer;
import com.lanternsoftware.util.dao.DaoEntity;
import com.lanternsoftware.util.dao.DaoProxyType;
import com.lanternsoftware.util.dao.DaoSerializer;
import java.util.Collections;
import java.util.List;
public class PowerSampleSerializer extends AbstractDaoSerializer<PowerSample>
{
@Override
public Class<PowerSample> getSupportedClass()
{
return PowerSample.class;
}
@Override
public List<DaoProxyType> getSupportedProxies() {
return Collections.singletonList(DaoProxyType.MONGO);
}
@Override
public DaoEntity toDaoEntity(PowerSample _o)
{
DaoEntity d = new DaoEntity();
d.put("nano_time", _o.getNanoTime());
d.put("cycle", _o.getCycle());
d.put("voltage", _o.getVoltage());
d.put("current", _o.getCurrent());
return d;
}
@Override
public PowerSample fromDaoEntity(DaoEntity _d)
{
PowerSample o = new PowerSample();
o.setNanoTime(DaoSerializer.getLong(_d, "nano_time"));
o.setCycle(DaoSerializer.getInteger(_d, "cycle"));
o.setVoltage(DaoSerializer.getDouble(_d, "voltage"));
o.setCurrent(DaoSerializer.getDouble(_d, "current"));
return o;
}
}

View File

@ -15,7 +15,6 @@ com.lanternsoftware.datamodel.currentmonitor.dao.BreakerPowerSerializer
com.lanternsoftware.datamodel.currentmonitor.dao.BreakerSerializer com.lanternsoftware.datamodel.currentmonitor.dao.BreakerSerializer
com.lanternsoftware.datamodel.currentmonitor.dao.ChargeSummarySerializer com.lanternsoftware.datamodel.currentmonitor.dao.ChargeSummarySerializer
com.lanternsoftware.datamodel.currentmonitor.dao.ChargeTotalSerializer com.lanternsoftware.datamodel.currentmonitor.dao.ChargeTotalSerializer
com.lanternsoftware.datamodel.currentmonitor.dao.EmailCredentialsSerializer
com.lanternsoftware.datamodel.currentmonitor.dao.EnergyBlockSerializer com.lanternsoftware.datamodel.currentmonitor.dao.EnergyBlockSerializer
com.lanternsoftware.datamodel.currentmonitor.dao.EnergySummarySerializer com.lanternsoftware.datamodel.currentmonitor.dao.EnergySummarySerializer
com.lanternsoftware.datamodel.currentmonitor.dao.EnergyTotalSerializer com.lanternsoftware.datamodel.currentmonitor.dao.EnergyTotalSerializer
@ -26,6 +25,3 @@ com.lanternsoftware.datamodel.currentmonitor.dao.MeterSerializer
com.lanternsoftware.datamodel.currentmonitor.dao.NetworkStatusSerializer com.lanternsoftware.datamodel.currentmonitor.dao.NetworkStatusSerializer
com.lanternsoftware.datamodel.currentmonitor.dao.SequenceSerializer com.lanternsoftware.datamodel.currentmonitor.dao.SequenceSerializer
com.lanternsoftware.datamodel.currentmonitor.dao.SignupResponseSerializer com.lanternsoftware.datamodel.currentmonitor.dao.SignupResponseSerializer
com.lanternsoftware.datamodel.currentmonitor.hub.dao.BreakerSampleSerializer
com.lanternsoftware.datamodel.currentmonitor.hub.dao.HubSampleSerializer
com.lanternsoftware.datamodel.currentmonitor.hub.dao.PowerSampleSerializer

View File

@ -1,41 +1,54 @@
<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"> <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> <modelVersion>4.0.0</modelVersion>
<groupId>com.lanternsoftware.currentmonitor</groupId>
<artifactId>lantern-service-currentmonitor</artifactId> <artifactId>lantern-service-currentmonitor</artifactId>
<packaging>war</packaging> <packaging>war</packaging>
<version>1.1.0</version> <version>1.0.0</version>
<name>lantern-service-currentmonitor</name> <name>lantern-service-currentmonitor</name>
<parent> <properties>
<groupId>com.lanternsoftware.currentmonitor</groupId> <maven.compiler.source>1.8</maven.compiler.source>
<artifactId>currentmonitor</artifactId> <maven.compiler.target>1.8</maven.compiler.target>
<version>1.1.0</version> </properties>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.google.api-client</groupId>
<artifactId>google-api-client-bom</artifactId>
<version>1.32.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>com.lanternsoftware.currentmonitor</groupId> <groupId>com.lanternsoftware.currentmonitor</groupId>
<artifactId>lantern-dataaccess-currentmonitor</artifactId> <artifactId>lantern-dataaccess-currentmonitor</artifactId>
<version>${cm.version}</version> <version>1.0.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.lanternsoftware.util</groupId> <groupId>com.lanternsoftware.util</groupId>
<artifactId>lantern-util-servlet</artifactId> <artifactId>lantern-util-servlet</artifactId>
<version>${util.version}</version> <version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.lanternsoftware.util</groupId>
<artifactId>lantern-util-cloudservices</artifactId>
<version>${util.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.lanternsoftware.util</groupId> <groupId>com.lanternsoftware.util</groupId>
<artifactId>lantern-util-http</artifactId> <artifactId>lantern-util-http</artifactId>
<version>${util.version}</version> <version>1.0.0</version>
<scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.lanternsoftware.rules</groupId> <groupId>com.lanternsoftware.rules</groupId>
<artifactId>lantern-service-rules</artifactId> <artifactId>lantern-service-rules</artifactId>
<version>${rules.version}</version> <version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.google.api-client</groupId>
<artifactId>google-api-client</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>javax</groupId> <groupId>javax</groupId>
@ -54,14 +67,9 @@
<version>1.2.3</version> <version>1.2.3</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.auth0</groupId> <groupId>com.sendgrid</groupId>
<artifactId>java-jwt</artifactId> <artifactId>sendgrid-java</artifactId>
<version>3.19.1</version> <version>4.7.2</version>
</dependency>
<dependency>
<groupId>com.mailjet</groupId>
<artifactId>mailjet-client</artifactId>
<version>4.2.0</version>
</dependency> </dependency>
</dependencies> </dependencies>
<build> <build>
@ -74,7 +82,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version> <version>3.2</version>
<executions> <executions>
<execution> <execution>
<goals> <goals>
@ -87,13 +95,13 @@
<optimize>true</optimize> <optimize>true</optimize>
<showDeprecation>true</showDeprecation> <showDeprecation>true</showDeprecation>
<encoding>UTF-8</encoding> <encoding>UTF-8</encoding>
<source>${maven.compiler.source}</source> <source>1.8</source>
<target>${maven.compiler.target}</target> <target>1.8</target>
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>
<artifactId>maven-war-plugin</artifactId> <artifactId>maven-war-plugin</artifactId>
<version>3.3.2</version> <version>2.5</version>
<configuration> <configuration>
<webResources> <webResources>
<resource> <resource>

View File

@ -6,9 +6,8 @@ import com.lanternsoftware.datamodel.currentmonitor.HubCommand;
import com.lanternsoftware.datamodel.currentmonitor.HubCommands; import com.lanternsoftware.datamodel.currentmonitor.HubCommands;
import com.lanternsoftware.rules.RulesEngine; import com.lanternsoftware.rules.RulesEngine;
import com.lanternsoftware.util.DateUtils; import com.lanternsoftware.util.DateUtils;
import com.lanternsoftware.util.dao.mongo.MongoConfig;
import com.lanternsoftware.util.external.LanternFiles; import com.lanternsoftware.util.external.LanternFiles;
import com.lanternsoftware.util.http.HttpFactory; import com.lanternsoftware.util.dao.mongo.MongoConfig;
import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener; import javax.servlet.ServletContextListener;
@ -18,12 +17,9 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.TimerTask; import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Globals implements ServletContextListener { public class Globals implements ServletContextListener {
public static CurrentMonitorDao dao; public static CurrentMonitorDao dao;
public static ExecutorService opsExecutor;
private static final Map<Integer, Map<Integer, List<HubCommand>>> commands = new HashMap<>(); private static final Map<Integer, Map<Integer, List<HubCommand>>> commands = new HashMap<>();
@Override @Override
@ -31,14 +27,11 @@ public class Globals implements ServletContextListener {
dao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.CONFIG_PATH + "mongo.cfg")); dao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.CONFIG_PATH + "mongo.cfg"));
RulesEngine.instance().start(); RulesEngine.instance().start();
RulesEngine.instance().schedule(new CommandTask(), 0); RulesEngine.instance().schedule(new CommandTask(), 0);
opsExecutor = Executors.newFixedThreadPool(7);
} }
@Override @Override
public void contextDestroyed(ServletContextEvent sce) { public void contextDestroyed(ServletContextEvent sce) {
opsExecutor.shutdown();
dao.shutdown(); dao.shutdown();
HttpFactory.shutdown();
RulesEngine.shutdown(); RulesEngine.shutdown();
} }

View File

@ -1,7 +0,0 @@
package com.lanternsoftware.currentmonitor.email;
import com.lanternsoftware.datamodel.currentmonitor.EmailCredentials;
public interface IEmailProvider {
int sendTextEmail(EmailCredentials _credentials, String _to, String _subject, String _message);
}

View File

@ -1,36 +0,0 @@
package com.lanternsoftware.currentmonitor.email;
import com.lanternsoftware.datamodel.currentmonitor.EmailCredentials;
import com.mailjet.client.ClientOptions;
import com.mailjet.client.MailjetClient;
import com.mailjet.client.MailjetRequest;
import com.mailjet.client.MailjetResponse;
import com.mailjet.client.resource.Emailv31;
import org.json.JSONArray;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MailJetProvider implements IEmailProvider {
protected static final Logger LOG = LoggerFactory.getLogger(MailJetProvider.class);
@Override
public int sendTextEmail(EmailCredentials _credentials, String _to, String _subject, String _message) {
MailjetClient client;
MailjetRequest request;
MailjetResponse response;
client = new MailjetClient(_credentials.getApiKey(), _credentials.getApiSecret(), new ClientOptions("v3.1"));
request = new MailjetRequest(Emailv31.resource).property(Emailv31.MESSAGES, new JSONArray().put(new JSONObject()
.put(Emailv31.Message.FROM, new JSONObject().put("Email", _credentials.getEmailFrom()).put("Name", "Lantern Power Monitor"))
.put(Emailv31.Message.TO, new JSONArray().put(new JSONObject().put("Email", _to)))
.put(Emailv31.Message.SUBJECT, _subject)
.put(Emailv31.Message.TEXTPART, _message)));
try {
response = client.post(request);
return response.getStatus();
} catch (Exception _e) {
LOG.error("Failed to send email", _e);
return 500;
}
}
}

View File

@ -1,26 +0,0 @@
package com.lanternsoftware.currentmonitor.email;
import com.lanternsoftware.datamodel.currentmonitor.EmailCredentials;
public class SendGridProvider implements IEmailProvider {
@Override
public int sendTextEmail(EmailCredentials _credentials, String _to, String _subject, String _message) {
/* Email to = new Email(email);
Content content = new Content("text/plain", "Reset your password using this link:\nhttps://lanternpowermonitor.com/currentmonitor/resetPassword/" + key);
Mail mail = new Mail(from, subject, to, content);
SendGrid sg = new SendGrid(api_key);
Request request = new Request();
try {
request.setMethod(Method.POST);
request.setEndpoint("mail/send");
request.setBody(mail.build());
Response response = sg.api(request);
LOG.info("Password reset email status: {}\nfrom: {}\nto: {}\nkey: {}\nhost: {}", response.getStatusCode(), from.getEmail(), to.getEmail(), api_key, sg.getHost());
zipBsonResponse(_resp, new DaoEntity("success", response.getStatusCode() == 200));
} catch (IOException ex) {
LOG.error("Failed to send password reset email", ex);
_resp.setStatus(500);
}*/
return 500;
}
}

View File

@ -1,15 +1,14 @@
package com.lanternsoftware.currentmonitor.servlet; package com.lanternsoftware.currentmonitor.servlet;
import com.lanternsoftware.currentmonitor.context.Globals; import com.lanternsoftware.currentmonitor.context.Globals;
import com.lanternsoftware.currentmonitor.util.GoogleAuthHelper;
import com.lanternsoftware.util.DateUtils; import com.lanternsoftware.util.DateUtils;
import com.lanternsoftware.util.NullUtils; import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.cloudservices.apple.AppleSSO;
import com.lanternsoftware.util.cloudservices.google.GoogleSSO;
import com.lanternsoftware.util.dao.DaoEntity; import com.lanternsoftware.util.dao.DaoEntity;
import com.lanternsoftware.util.dao.DaoSerializer;
import com.lanternsoftware.util.external.LanternFiles;
import com.lanternsoftware.util.servlet.BasicAuth; import com.lanternsoftware.util.servlet.BasicAuth;
import com.lanternsoftware.util.servlet.LanternServlet; import com.lanternsoftware.util.servlet.LanternServlet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.annotation.WebServlet; import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -17,27 +16,19 @@ import javax.servlet.http.HttpServletResponse;
@WebServlet("/auth/*") @WebServlet("/auth/*")
public class AuthServlet extends LanternServlet { public class AuthServlet extends LanternServlet {
private static final GoogleSSO googleSSO = new GoogleSSO(LanternFiles.CONFIG_PATH + "google_sso.txt"); private static final Logger logger = LoggerFactory.getLogger(AuthServlet.class);
private static final AppleSSO appleSSO = new AppleSSO(LanternFiles.CONFIG_PATH + "apple_sso.txt");
@Override @Override
protected void doGet(HttpServletRequest _req, HttpServletResponse _rep) { protected void doGet(HttpServletRequest _req, HttpServletResponse _rep) {
String authCode = _req.getHeader("auth_code"); String authCode = _req.getHeader("auth_code");
String idToken = _req.getHeader("id_token"); if (NullUtils.isEmpty(authCode)) {
String email = null;
if (NullUtils.isNotEmpty(idToken))
email = appleSSO.getEmailFromIdToken(idToken);
else if (NullUtils.isNotEmpty(authCode))
authCode = Globals.dao.exchangeAuthCode(authCode, DaoSerializer.toInteger(_req.getHeader("override_account")));
else {
BasicAuth auth = new BasicAuth(_req); BasicAuth auth = new BasicAuth(_req);
if (NullUtils.isEqual(auth.getUsername(), "googlesso")) if (NullUtils.isEqual(auth.getUsername(), "googlesso")) {
email = googleSSO.signin(auth.getPassword()); logger.info("Attempting google SSO");
else authCode = GoogleAuthHelper.signin(auth.getPassword(), DateUtils.fromTimeZoneId(_req.getHeader("timezone")));
} else
authCode = Globals.dao.authenticateAccount(auth.getUsername(), auth.getPassword()); authCode = Globals.dao.authenticateAccount(auth.getUsername(), auth.getPassword());
} }
if (NullUtils.isNotEmpty(email))
authCode = Globals.dao.getAuthCodeForEmail(email, DateUtils.fromTimeZoneId(_req.getHeader("timezone")));
DaoEntity rep = new DaoEntity("auth_code", authCode).and("timezone", Globals.dao.getTimeZoneForAccount(authCode)); DaoEntity rep = new DaoEntity("auth_code", authCode).and("timezone", Globals.dao.getTimeZoneForAccount(authCode));
if (isPath(_req, 0, "bin")) if (isPath(_req, 0, "bin"))
zipBsonResponse(_rep, rep); zipBsonResponse(_rep, rep);

View File

@ -4,7 +4,6 @@ import com.lanternsoftware.currentmonitor.context.Globals;
import com.lanternsoftware.datamodel.currentmonitor.BreakerConfig; import com.lanternsoftware.datamodel.currentmonitor.BreakerConfig;
import com.lanternsoftware.datamodel.currentmonitor.HubCommand; import com.lanternsoftware.datamodel.currentmonitor.HubCommand;
import com.lanternsoftware.datamodel.currentmonitor.HubConfigCharacteristic; import com.lanternsoftware.datamodel.currentmonitor.HubConfigCharacteristic;
import com.lanternsoftware.rules.RulesEngine;
import com.lanternsoftware.util.dao.auth.AuthCode; import com.lanternsoftware.util.dao.auth.AuthCode;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -41,8 +40,6 @@ public class ConfigServlet extends SecureServiceServlet {
if ((oldConfig == null) || !oldConfig.isIdentical(config)) if ((oldConfig == null) || !oldConfig.isIdentical(config))
Globals.dao.putHubCommand(new HubCommand(config.getAccountId(), HubConfigCharacteristic.ReloadConfig, null)); Globals.dao.putHubCommand(new HubCommand(config.getAccountId(), HubConfigCharacteristic.ReloadConfig, null));
Globals.dao.putConfig(config); Globals.dao.putConfig(config);
config = Globals.dao.getMergedConfig(_authCode); zipBsonResponse(_rep, Globals.dao.getMergedConfig(_authCode));
RulesEngine.instance().sendFcmMessage(config.getAccountId(), config);
zipBsonResponse(_rep, config);
} }
} }

View File

@ -17,14 +17,13 @@ public class RebuildSummariesServlet extends SecureServiceServlet {
if (_authCode.getAccountId() == 100) { if (_authCode.getAccountId() == 100) {
String[] path = path(_req); String[] path = path(_req);
if (path.length > 0) { if (path.length > 0) {
Globals.opsExecutor.submit(() -> Globals.dao.rebuildSummaries(DaoSerializer.toInteger(CollectionUtils.get(path, 0)))); Globals.dao.rebuildSummariesAsync(DaoSerializer.toInteger(CollectionUtils.get(path, 0)));
} }
else { else {
for (String sId : Globals.dao.getProxy().queryForField(Account.class, null, "_id")) { for (String sId : Globals.dao.getProxy().queryForField(Account.class, null, "_id")) {
int id = DaoSerializer.toInteger(sId); int id = DaoSerializer.toInteger(sId);
if (id != 0) { if (id != 0)
Globals.opsExecutor.submit(() -> Globals.dao.rebuildSummaries(id)); Globals.dao.rebuildSummariesAsync(id);
}
} }
} }
} }

View File

@ -1,19 +1,22 @@
package com.lanternsoftware.currentmonitor.servlet; package com.lanternsoftware.currentmonitor.servlet;
import com.lanternsoftware.currentmonitor.context.Globals; import com.lanternsoftware.currentmonitor.context.Globals;
import com.lanternsoftware.currentmonitor.email.IEmailProvider;
import com.lanternsoftware.currentmonitor.email.MailJetProvider;
import com.lanternsoftware.datamodel.currentmonitor.Account;
import com.lanternsoftware.datamodel.currentmonitor.EmailCredentials;
import com.lanternsoftware.util.CollectionUtils; import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.external.LanternFiles;
import com.lanternsoftware.util.NullUtils; import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.ResourceLoader; import com.lanternsoftware.util.ResourceLoader;
import com.lanternsoftware.util.dao.DaoEntity; import com.lanternsoftware.util.dao.DaoEntity;
import com.lanternsoftware.util.dao.DaoSerializer; import com.lanternsoftware.util.dao.DaoSerializer;
import com.lanternsoftware.util.email.EmailValidator; import com.lanternsoftware.util.email.EmailValidator;
import com.lanternsoftware.util.external.LanternFiles;
import com.lanternsoftware.util.servlet.FreemarkerConfigUtil; import com.lanternsoftware.util.servlet.FreemarkerConfigUtil;
import com.lanternsoftware.util.servlet.FreemarkerServlet; import com.lanternsoftware.util.servlet.FreemarkerServlet;
import com.sendgrid.Method;
import com.sendgrid.Request;
import com.sendgrid.Response;
import com.sendgrid.SendGrid;
import com.sendgrid.helpers.mail.Mail;
import com.sendgrid.helpers.mail.objects.Content;
import com.sendgrid.helpers.mail.objects.Email;
import freemarker.template.Configuration; import freemarker.template.Configuration;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -22,13 +25,13 @@ import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import java.io.IOException;
@WebServlet("/resetPassword/*") @WebServlet("/resetPassword/*")
public class ResetPasswordServlet extends FreemarkerServlet { public class ResetPasswordServlet extends FreemarkerServlet {
protected static final Logger LOG = LoggerFactory.getLogger(ResetPasswordServlet.class); protected static final Logger LOG = LoggerFactory.getLogger(ResetPasswordServlet.class);
protected static final Configuration CONFIG = FreemarkerConfigUtil.createConfig(ResetPasswordServlet.class, "/templates", 100); protected static final Configuration CONFIG = FreemarkerConfigUtil.createConfig(ResetPasswordServlet.class, "/templates", 100);
protected static final EmailCredentials credentials = DaoSerializer.parse(ResourceLoader.loadFileAsString(LanternFiles.CONFIG_PATH + "email.json"), EmailCredentials.class); protected static final String api_key = ResourceLoader.loadFileAsString(LanternFiles.CONFIG_PATH + "sendgrid.txt");
protected static final IEmailProvider provider = new MailJetProvider();
@Override @Override
protected Configuration getFreemarkerConfig() { protected Configuration getFreemarkerConfig() {
@ -60,11 +63,25 @@ public class ResetPasswordServlet extends FreemarkerServlet {
} else { } else {
DaoEntity payload = getRequestZipBson(_req); DaoEntity payload = getRequestZipBson(_req);
String email = DaoSerializer.getString(payload, "email"); String email = DaoSerializer.getString(payload, "email");
Account account = Globals.dao.getAccountByUsername(email); if (EmailValidator.getInstance().isValid(email)) {
if ((account != null) && EmailValidator.getInstance().isValid(email)) {
String key = Globals.dao.addPasswordResetKey(email); String key = Globals.dao.addPasswordResetKey(email);
int status = provider.sendTextEmail(credentials, email, "Password Reset - Lantern Power Monitor", "Reset your password using this link:\n" + credentials.getServerUrlBase() + "resetPassword/" + key); Email from = new Email("info@lanternsoftware.com");
zipBsonResponse(_resp, new DaoEntity("success", status == 200)); String subject = "Password Reset - Lantern Power Monitor";
Email to = new Email(email);
Content content = new Content("text/plain", "Reset your password using this link:\nhttps://lanternsoftware.com/currentmonitor/resetPassword/" + key);
Mail mail = new Mail(from, subject, to, content);
SendGrid sg = new SendGrid(api_key);
Request request = new Request();
try {
request.setMethod(Method.POST);
request.setEndpoint("mail/send");
request.setBody(mail.build());
Response response = sg.api(request);
zipBsonResponse(_resp, new DaoEntity("success", response.getStatusCode() == 200));
} catch (IOException ex) {
LOG.error("Failed to send password reset email", ex);
_resp.setStatus(500);
}
} }
else else
_resp.setStatus(400); _resp.setStatus(400);

View File

@ -1,21 +0,0 @@
package com.lanternsoftware.currentmonitor.servlet;
import com.lanternsoftware.currentmonitor.context.Globals;
import com.lanternsoftware.datamodel.currentmonitor.hub.HubSample;
import com.lanternsoftware.util.dao.auth.AuthCode;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/sample")
public class SampleServlet extends SecureServiceServlet {
@Override
protected void post(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
HubSample sample = getRequestPayload(_req, HubSample.class);
if (sample == null)
return;
sample.setAccountId(_authCode.getAccountId());
Globals.dao.putHubSample(sample);
}
}

View File

@ -14,27 +14,26 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.util.Locale; import java.util.Locale;
@WebServlet("/signup/*") @WebServlet("/signup")
public class SignupServlet extends LanternServlet { public class SignupServlet extends LanternServlet {
@Override @Override
protected void doGet(HttpServletRequest _req, HttpServletResponse _rep) { protected void doGet(HttpServletRequest _req, HttpServletResponse _rep) {
boolean binary = isPath(_req, 0, "bin");
BasicAuth auth = new BasicAuth(_req); BasicAuth auth = new BasicAuth(_req);
Account acct = Globals.dao.getAccountByUsername(auth.getUsername().toLowerCase().trim()); Account acct = Globals.dao.getAccountByUsername(auth.getUsername().toLowerCase().trim());
if (acct != null) { if (acct != null) {
jsonResponse(_rep, SignupResponse.error("An account for " + auth.getUsername() + " already exists"), binary); jsonResponse(_rep, SignupResponse.error("An account for " + auth.getUsername() + " already exists"));
return; return;
} }
if (!EmailValidator.getInstance().isValid(auth.getUsername())) { if (!EmailValidator.getInstance().isValid(auth.getUsername())) {
jsonResponse(_rep, SignupResponse.error(auth.getUsername() + " is not a valid email address"), binary); jsonResponse(_rep, SignupResponse.error(auth.getUsername() + " is not a valid email address"));
return; return;
} }
if (NullUtils.length(auth.getPassword()) < 8) { if (NullUtils.length(auth.getPassword()) < 8) {
jsonResponse(_rep, SignupResponse.error("Your password must be at least 8 characters long"), binary); jsonResponse(_rep, SignupResponse.error("Your password must be at least 8 characters long"));
return; return;
} }
if (NullUtils.isEqual("password", auth.getPassword())) { if (NullUtils.isEqual("password", auth.getPassword())) {
jsonResponse(_rep, SignupResponse.error("Seriously? \"password\"? Come on."), binary); jsonResponse(_rep, SignupResponse.error("Seriously? \"password\"? Come on."));
return; return;
} }
acct = new Account(); acct = new Account();
@ -43,6 +42,6 @@ public class SignupServlet extends LanternServlet {
acct.setTimezone(DateUtils.fromTimeZoneId(_req.getHeader("timezone")).getID()); acct.setTimezone(DateUtils.fromTimeZoneId(_req.getHeader("timezone")).getID());
Globals.dao.putAccount(acct); Globals.dao.putAccount(acct);
String authCode = Globals.dao.authenticateAccount(auth.getUsername(), auth.getPassword()); String authCode = Globals.dao.authenticateAccount(auth.getUsername(), auth.getPassword());
jsonResponse(_rep, SignupResponse.success(authCode, acct.getTimezone()), binary); jsonResponse(_rep, SignupResponse.success(authCode, acct.getTimezone()));
} }
} }

View File

@ -1,56 +0,0 @@
package com.lanternsoftware.currentmonitor.servlet.console;
import com.lanternsoftware.currentmonitor.context.Globals;
import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.dao.DaoSerializer;
import com.lanternsoftware.util.dao.auth.AuthCode;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public abstract class AuthenticatedConsoleServlet extends SecureConsoleServlet {
@Override
protected void get(HttpServletRequest _req, HttpServletResponse _rep) {
AuthCode code = getAuthCode(_req, _rep);
if (code != null)
get(code, _req, _rep);
}
protected void get(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
}
@Override
protected void post(HttpServletRequest _req, HttpServletResponse _rep) {
AuthCode code = getAuthCode(_req, _rep);
if (code != null)
post(code, _req, _rep);
}
private AuthCode getAuthCode(HttpServletRequest _req, HttpServletResponse _rep) {
String sRequestURL = _req.getRequestURL().toString();
String sURL = sRequestURL.replaceFirst("http://", "https://");
if (!sURL.equals(sRequestURL)) {
String sQuery = _req.getQueryString();
if (NullUtils.isNotEmpty(sQuery))
sURL += "?" + sQuery;
redirect(_rep, sURL);
return null;
}
AuthCode authCode = Globals.dao.decryptAuthCode(DaoSerializer.toString(_req.getSession().getAttribute("auth_code")));
if (authCode == null) {
Cookie authCookie = CollectionUtils.filterOne(CollectionUtils.asArrayList(_req.getCookies()), _c-> NullUtils.isEqual(_c.getName(), "auth_code"));
if (authCookie != null)
authCode = Globals.dao.decryptAuthCode(authCookie.getValue());
}
if (authCode == null) {
redirect(_rep, _req.getContextPath() + "/login");
return null;
}
return authCode;
}
protected void post(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
}
}

View File

@ -9,7 +9,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
@WebServlet("") @WebServlet("")
public class ConsoleServlet extends AuthenticatedConsoleServlet { public class ConsoleServlet extends SecureConsoleServlet {
private static final Logger logger = LoggerFactory.getLogger(ConsoleServlet.class); private static final Logger logger = LoggerFactory.getLogger(ConsoleServlet.class);
@Override @Override

View File

@ -40,7 +40,7 @@ import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream; import java.util.zip.ZipOutputStream;
@WebServlet("/export/*") @WebServlet("/export/*")
public class ExportServlet extends AuthenticatedConsoleServlet { public class ExportServlet extends SecureConsoleServlet {
private static final Logger logger = LoggerFactory.getLogger(ExportServlet.class); private static final Logger logger = LoggerFactory.getLogger(ExportServlet.class);
@Override @Override

View File

@ -1,10 +1,8 @@
package com.lanternsoftware.currentmonitor.servlet.console; package com.lanternsoftware.currentmonitor.servlet.console;
import com.lanternsoftware.currentmonitor.context.Globals; import com.lanternsoftware.currentmonitor.servlet.FreemarkerCMServlet;
import com.lanternsoftware.util.DateUtils; import com.lanternsoftware.currentmonitor.util.GoogleAuthHelper;
import com.lanternsoftware.util.NullUtils; import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.cloudservices.google.GoogleSSO;
import com.lanternsoftware.util.external.LanternFiles;
import javax.servlet.annotation.WebServlet; import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie; import javax.servlet.http.Cookie;
@ -12,28 +10,23 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
@WebServlet("/gso") @WebServlet("/gso")
public class GsoServlet extends SecureConsoleServlet { public class GsoServlet extends FreemarkerCMServlet {
private static final GoogleSSO googleSSO = new GoogleSSO(LanternFiles.CONFIG_PATH + "google_sso.txt");
@Override @Override
protected void get(HttpServletRequest _req, HttpServletResponse _rep) { protected void doGet(HttpServletRequest _req, HttpServletResponse _rep) {
render(_rep, "login.ftl", model(_req)); render(_rep, "login.ftl", model(_req));
} }
@Override @Override
protected void post(HttpServletRequest _req, HttpServletResponse _rep) { protected void doPost(HttpServletRequest _req, HttpServletResponse _rep) {
String code = getRequestPayloadAsString(_req); String code = getRequestPayloadAsString(_req);
if (NullUtils.isNotEmpty(code)) { if (NullUtils.isNotEmpty(code)) {
String email = googleSSO.signin(code); String authCode = GoogleAuthHelper.signin(code, null);
if (NullUtils.isNotEmpty(email)) { if (NullUtils.isNotEmpty(authCode)) {
String authCode = Globals.dao.getAuthCodeForEmail(email, DateUtils.fromTimeZoneId(_req.getHeader("timezone"))); Cookie authCookie = new Cookie("auth_code", authCode);
if (NullUtils.isNotEmpty(authCode)) { authCookie.setMaxAge(157680000);
Cookie authCookie = new Cookie("auth_code", authCode); authCookie.setSecure(true);
authCookie.setMaxAge(157680000); _rep.addCookie(authCookie);
authCookie.setSecure(true); _req.getSession().setAttribute("auth_code", authCode);
_rep.addCookie(authCookie);
_req.getSession().setAttribute("auth_code", authCode);
}
} }
} }
} }

View File

@ -1,22 +1,31 @@
package com.lanternsoftware.currentmonitor.servlet.console; package com.lanternsoftware.currentmonitor.servlet.console;
import com.lanternsoftware.currentmonitor.context.Globals; import com.lanternsoftware.currentmonitor.context.Globals;
import com.lanternsoftware.currentmonitor.servlet.FreemarkerCMServlet;
import com.lanternsoftware.currentmonitor.util.GoogleAuthHelper;
import com.lanternsoftware.util.DateUtils;
import com.lanternsoftware.util.NullUtils; import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.dao.DaoEntity;
import com.lanternsoftware.util.dao.DaoSerializer;
import com.lanternsoftware.util.dao.auth.AuthCode;
import com.lanternsoftware.util.servlet.LanternServlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet; import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie; import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/login") @WebServlet("/login")
public class LoginServlet extends SecureConsoleServlet { public class LoginServlet extends FreemarkerCMServlet {
@Override @Override
protected void get(HttpServletRequest _req, HttpServletResponse _rep) { protected void doGet(HttpServletRequest _req, HttpServletResponse _rep) {
render(_rep, "login.ftl", model(_req)); render(_rep, "login.ftl", model(_req));
} }
@Override @Override
protected void post(HttpServletRequest _req, HttpServletResponse _rep) { protected void doPost(HttpServletRequest _req, HttpServletResponse _rep) {
String username = _req.getParameter("username"); String username = _req.getParameter("username");
String password = _req.getParameter("password"); String password = _req.getParameter("password");
String authCode = Globals.dao.authenticateAccount(username, password); String authCode = Globals.dao.authenticateAccount(username, password);

View File

@ -1,14 +1,18 @@
package com.lanternsoftware.currentmonitor.servlet.console; package com.lanternsoftware.currentmonitor.servlet.console;
import com.lanternsoftware.currentmonitor.servlet.FreemarkerCMServlet;
import com.lanternsoftware.currentmonitor.util.GoogleAuthHelper;
import com.lanternsoftware.util.NullUtils;
import javax.servlet.annotation.WebServlet; import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie; import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
@WebServlet("/logout") @WebServlet("/logout")
public class LogoutServlet extends AuthenticatedConsoleServlet { public class LogoutServlet extends FreemarkerCMServlet {
@Override @Override
protected void get(HttpServletRequest _req, HttpServletResponse _rep) { protected void doGet(HttpServletRequest _req, HttpServletResponse _rep) {
_req.getSession().removeAttribute("auth_code"); _req.getSession().removeAttribute("auth_code");
Cookie authCookie = new Cookie("auth_code", ""); Cookie authCookie = new Cookie("auth_code", "");
authCookie.setMaxAge(0); authCookie.setMaxAge(0);
@ -18,6 +22,6 @@ public class LogoutServlet extends AuthenticatedConsoleServlet {
} }
@Override @Override
protected void post(HttpServletRequest _req, HttpServletResponse _rep) { protected void doPost(HttpServletRequest _req, HttpServletResponse _rep) {
} }
} }

View File

@ -1,40 +1,48 @@
package com.lanternsoftware.currentmonitor.servlet.console; package com.lanternsoftware.currentmonitor.servlet.console;
import com.lanternsoftware.currentmonitor.context.Globals;
import com.lanternsoftware.currentmonitor.servlet.FreemarkerCMServlet; import com.lanternsoftware.currentmonitor.servlet.FreemarkerCMServlet;
import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.NullUtils; import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.dao.DaoSerializer;
import com.lanternsoftware.util.dao.auth.AuthCode;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
public abstract class SecureConsoleServlet extends FreemarkerCMServlet { public abstract class SecureConsoleServlet extends FreemarkerCMServlet {
@Override @Override
protected void doGet(HttpServletRequest _req, HttpServletResponse _rep) { protected void doGet(HttpServletRequest _req, HttpServletResponse _rep) {
if (isSecure(_req, _rep)) AuthCode code = getAuthCode(_req, _rep);
get(_req, _rep); if (code != null)
get(code, _req, _rep);
} }
protected void get(HttpServletRequest _req, HttpServletResponse _rep) { protected void get(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
} }
@Override @Override
protected void doPost(HttpServletRequest _req, HttpServletResponse _rep) { protected void doPost(HttpServletRequest _req, HttpServletResponse _rep) {
if (isSecure(_req, _rep)) AuthCode code = getAuthCode(_req, _rep);
post(_req, _rep); if (code != null)
post(code, _req, _rep);
} }
protected void post(HttpServletRequest _req, HttpServletResponse _rep) { private AuthCode getAuthCode(HttpServletRequest _req, HttpServletResponse _rep) {
} AuthCode authCode = Globals.dao.decryptAuthCode(DaoSerializer.toString(_req.getSession().getAttribute("auth_code")));
if (authCode == null) {
private boolean isSecure(HttpServletRequest _req, HttpServletResponse _rep) { Cookie authCookie = CollectionUtils.filterOne(CollectionUtils.asArrayList(_req.getCookies()), _c-> NullUtils.isEqual(_c.getName(), "auth_code"));
String sRequestURL = _req.getRequestURL().toString(); if (authCookie != null)
String sURL = sRequestURL.replaceFirst("http://", "https://"); authCode = Globals.dao.decryptAuthCode(authCookie.getValue());
if (!sURL.equals(sRequestURL)) {
String sQuery = _req.getQueryString();
if (NullUtils.isNotEmpty(sQuery))
sURL += "?" + sQuery;
redirect(_rep, sURL);
return false;
} }
return true; if (authCode == null) {
redirect(_rep, _req.getContextPath() + "/login");
return null;
}
return authCode;
}
protected void post(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
} }
} }

View File

@ -0,0 +1,42 @@
package com.lanternsoftware.currentmonitor.util;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeTokenRequest;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.gson.GsonFactory;
import com.lanternsoftware.currentmonitor.context.Globals;
import com.lanternsoftware.util.external.LanternFiles;
import com.lanternsoftware.util.ResourceLoader;
import com.lanternsoftware.util.dao.DaoEntity;
import com.lanternsoftware.util.dao.DaoSerializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.TimeZone;
public class GoogleAuthHelper {
private static final Logger logger = LoggerFactory.getLogger(GoogleAuthHelper.class);
private static final NetHttpTransport transport = new NetHttpTransport();
private static final String googleClientId;
private static final String googleClientSecret;
static {
DaoEntity google = DaoSerializer.parse(ResourceLoader.loadFileAsString(LanternFiles.CONFIG_PATH + "google_sso.txt"));
googleClientId = DaoSerializer.getString(google, "id");
googleClientSecret = DaoSerializer.getString(google, "secret");
}
public static String signin(String _code, TimeZone _tz) {
try {
GoogleTokenResponse tokenResponse = new GoogleAuthorizationCodeTokenRequest(transport, new GsonFactory(), "https://oauth2.googleapis.com/token", googleClientId, googleClientSecret, _code, "postmessage").execute();
if (tokenResponse != null) {
GoogleIdToken idToken = tokenResponse.parseIdToken();
if (idToken != null)
return Globals.dao.getAuthCodeForEmail(idToken.getPayload().getEmail(), _tz);
}
} catch (Exception _e) {
logger.error("Failed to validate google auth code", _e);
}
return null;
}
}

View File

@ -3,7 +3,7 @@
<property name="log.pattern" value="%date %-5level %logger{0} - %message%n"/> <property name="log.pattern" value="%date %-5level %logger{0} - %message%n"/>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/opt/tomcat/log/log.txt</file> <file>/opt/tomcat/logs/log.txt</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>/opt/tomcat/log/log.%d{yyyy-MM-dd}.%i.txt</fileNamePattern> <fileNamePattern>/opt/tomcat/log/log.%d{yyyy-MM-dd}.%i.txt</fileNamePattern>
<maxFileSize>20MB</maxFileSize> <maxFileSize>20MB</maxFileSize>

View File

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

View File

@ -1,37 +0,0 @@
package com.lanternsoftware.currentmonitor;
import com.lanternsoftware.datamodel.currentmonitor.BreakerConfig;
import com.lanternsoftware.datamodel.currentmonitor.EnergySummary;
import com.lanternsoftware.util.DateUtils;
import com.lanternsoftware.util.dao.DaoSerializer;
import com.lanternsoftware.util.http.HttpPool;
import com.lanternsoftware.util.servlet.BasicAuth;
import org.apache.http.client.methods.HttpGet;
import java.util.Date;
import java.util.TimeZone;
public class GetEnergySummary {
public static void main(String[] args) {
HttpPool pool = new HttpPool(10, 10, 10000, 10000, 10000);
HttpGet authRequest = new HttpGet("https://lanternpowermonitor.com/currentmonitor/auth");
authRequest.addHeader("Authorization", BasicAuth.toHeader("<username>", "<password>"));
String authRep = pool.executeToString(authRequest);
String authCode = DaoSerializer.getString(DaoSerializer.parse(authRep), "auth_code");
HttpGet configRequest = new HttpGet("https://lanternpowermonitor.com/currentmonitor/config");
configRequest.addHeader("auth_code", authCode);
String configRep = pool.executeToString(configRequest);
BreakerConfig config = DaoSerializer.parse(configRep, BreakerConfig.class);
Date day = DateUtils.date(6, 5, 2022, TimeZone.getTimeZone("America/Chicago"));
HttpGet summaryRequest = new HttpGet("https://lanternpowermonitor.com/currentmonitor/energy/" + config.getRootGroup().getId() + "/DAY/" + day.getTime());
summaryRequest.addHeader("auth_code", authCode);
EnergySummary summary = DaoSerializer.fromZipBson(pool.executeToByteArray(summaryRequest), EnergySummary.class);
System.out.println(DaoSerializer.toJson(summary));
pool.shutdown();
}
}

View File

@ -4,16 +4,14 @@
<groupId>com.lanternsoftware.currentmonitor</groupId> <groupId>com.lanternsoftware.currentmonitor</groupId>
<artifactId>currentmonitor</artifactId> <artifactId>currentmonitor</artifactId>
<name>currentmonitor</name> <name>currentmonitor</name>
<version>1.1.0</version> <version>1.0.0</version>
<parent> <properties>
<groupId>com.lanternsoftware</groupId> <maven.compiler.source>1.8</maven.compiler.source>
<artifactId>LanternPowerMonitor</artifactId> <maven.compiler.target>1.8</maven.compiler.target>
<version>1.0.0</version> </properties>
</parent>
<modules> <modules>
<module>lantern-config-currentmonitor</module>
<module>lantern-currentmonitor</module> <module>lantern-currentmonitor</module>
<module>lantern-dataaccess-currentmonitor</module> <module>lantern-dataaccess-currentmonitor</module>
<module>lantern-datamodel-currentmonitor</module> <module>lantern-datamodel-currentmonitor</module>

File diff suppressed because one or more lines are too long

View File

@ -1,24 +1,25 @@
G04 Layer: BoardOutline* G04 Layer: BoardOutline*
G04 EasyEDA v6.4.25, 2022-04-08T13:20:52--5:00* G04 EasyEDA v6.4.0, 2020-07-14T23:16:01--5:00*
G04 6dc5d916f8a9456ea10d5ff2c879efc5,9df6f537d2f94b3ba0ed850023b5714d,10*
G04 Gerber Generator version 0.2* G04 Gerber Generator version 0.2*
G04 Scale: 100 percent, Rotated: No, Reflected: No * G04 Scale: 100 percent, Rotated: No, Reflected: No *
G04 Dimensions in millimeters * G04 Dimensions in millimeters *
G04 leading zeros omitted , absolute positions ,4 integer and 5 decimal * G04 leading zeros omitted , absolute positions ,3 integer and 3 decimal *
%FSLAX45Y45*% %FSLAX33Y33*%
%MOMM*% %MOMM*%
G90*
G71D02*
%ADD10C,0.2540*% %ADD10C,0.254000*%
D10* G54D10*
X0Y0D02* G01X0Y56000D02*
G01* G01X64999Y56000D01*
X6499994Y0D01* G01X64999Y0D01*
X6499994Y-5600006D01* G01X64999Y0D02*
X6499994Y-5600006D02* G01X0Y0D01*
G01* G01X0Y0D02*
X0Y-5600006D01* G01X0Y56000D01*
X0Y-5600006D02*
G01*
X0Y0D01*
%LPD*% %LPD*%
M00*
M02* M02*

View File

@ -1,568 +1,382 @@
G04 Layer: BottomLayer* G04 Layer: BottomLayer*
G04 EasyEDA v6.4.25, 2022-04-08T13:20:52--5:00* G04 EasyEDA v6.4.0, 2020-07-14T23:16:01--5:00*
G04 6dc5d916f8a9456ea10d5ff2c879efc5,9df6f537d2f94b3ba0ed850023b5714d,10*
G04 Gerber Generator version 0.2* G04 Gerber Generator version 0.2*
G04 Scale: 100 percent, Rotated: No, Reflected: No * G04 Scale: 100 percent, Rotated: No, Reflected: No *
G04 Dimensions in millimeters * G04 Dimensions in millimeters *
G04 leading zeros omitted , absolute positions ,4 integer and 5 decimal * G04 leading zeros omitted , absolute positions ,3 integer and 3 decimal *
%FSLAX45Y45*% %FSLAX33Y33*%
%MOMM*% %MOMM*%
G90*
G71D02*
%ADD10C,0.2540*% %ADD10C,0.254000*%
%ADD12C,0.6096*% %ADD12C,0.609600*%
%ADD13R,1.8000X1.8000*% %ADD13R,1.799996X1.799996*%
%ADD14C,1.2000*% %ADD14C,1.799996*%
%ADD15C,1.5240*% %ADD15C,1.199998*%
%ADD16C,1.8000*% %ADD16C,1.524000*%
%ADD17C,1.6000*% %ADD17C,1.599997*%
%LPD*% %LPD*%
D10* G54D10*
X1545081Y-4261865D02* G01X8369Y53769D02*
G01* G01X9639Y52499D01*
X2353056Y-4261865D01* G01X11674Y52500D01*
X2435097Y-4180077D01* G01X12174Y52000D01*
X3668999Y-2127001D02* G01X12174Y48875D01*
G01* G01X12999Y48141D01*
X3303000Y-2127001D01* G01X12999Y47031D01*
X3300001Y-2130000D01* G01X59499Y21125D02*
X1299972Y-1927097D02* G01X59499Y21250D01*
G01* G01X58750Y21999D01*
X1299972Y-2769107D01* G01X51501Y21999D01*
X1299997Y-2768983D02* G01X50250Y23250D01*
G01* G01X50250Y34000D01*
X1299997Y-3045007D01* G01X46979Y37270D01*
X2434991Y-4180001D01* G01X44310Y37270D01*
X3199993Y-1754997D02* G01X59500Y12124D02*
G01* G01X59500Y12250D01*
X3317996Y-1873001D01* G01X58000Y13750D01*
X3668999Y-1873001D01* G01X51499Y13750D01*
X3050031Y-1754631D02* G01X48749Y16500D01*
G01* G01X48749Y32500D01*
X3049993Y-1931995D01* G01X46519Y34730D01*
X2831000Y-2127001D01* G01X44310Y34730D01*
X2831084Y-2126995D01* G01X38874Y5499D02*
X3630929Y-223012D02* G01X38874Y6124D01*
G01* G01X46250Y13500D01*
X3757993Y-348000D01* G01X46250Y28750D01*
X3757993Y-659998D01* G01X45349Y29650D01*
X3999991Y-899921D01* G01X44310Y29650D01*
X3999991Y-1249934D01* G01X47873Y5499D02*
X3884929Y-1364995D01* G01X47500Y5499D01*
X3669029Y-1364995D01* G01X45999Y7000D01*
X3669035Y-1618995D02* G01X45999Y10749D01*
G01* G01X47500Y12251D01*
X3668044Y-1618005D01* G01X47500Y30749D01*
X3121990Y-1618005D01* G01X46060Y32190D01*
X3121913Y-1617979D02* G01X44310Y32190D01*
G01* G01X59499Y30125D02*
X3121992Y-2249995D01* G01X59499Y30249D01*
X2987995Y-2381994D01* G01X57749Y31999D01*
X2831084Y-2380995D01* G01X55250Y31999D01*
X3376929Y-477012D02* G01X47439Y39810D01*
G01* G01X44310Y39810D01*
X3377994Y-629998D01* G01X59500Y39124D02*
X3050001Y-940000D01* G01X59500Y39250D01*
X3050001Y-1754728D01* G01X57749Y41000D01*
X5950000Y-787527D02* G01X53750Y41000D01*
G01* G01X52399Y42350D01*
X5950000Y-774999D01* G01X44310Y42350D01*
X5850000Y-674999D01* G01X59500Y48124D02*
X5375000Y-674999D01* G01X59500Y48250D01*
X4939004Y-1110995D01* G01X58500Y49250D01*
X4431004Y-1110995D01* G01X53750Y49250D01*
X5950000Y-1687525D02* G01X49390Y44890D01*
G01* G01X44310Y44890D01*
X5950000Y-1675000D01* G01X33769Y51229D02*
X5774999Y-1499999D01* G01X33779Y49700D01*
X5375000Y-1499999D01* G01X30500Y46600D01*
X5239997Y-1364995D01* G01X30500Y38452D01*
X4431004Y-1364995D01* G01X31219Y39820D02*
X5949950Y-2587497D02* G01X31219Y33500D01*
G01* G01X29879Y32180D01*
X5949950Y-2575052D01* G01X28310Y32190D01*
X5774943Y-2400045D01* G01X36690Y39810D02*
X5525008Y-2400045D01* G01X36680Y39820D01*
X4743958Y-1618995D01* G01X31219Y39820D01*
X4431029Y-1618995D01* G01X36309Y53769D02*
X4787391Y-5050027D02* G01X37579Y52520D01*
G01* G01X37579Y49400D01*
X4750054Y-5050027D01* G01X39999Y47000D01*
X4599940Y-4899913D01* G01X39999Y43500D01*
X4599940Y-4525009D01* G01X38849Y42350D01*
X4750054Y-4374895D01* G01X36690Y42350D01*
X4750054Y-2525013D01* G01X30500Y38453D02*
X4606036Y-2380995D01* G01X30499Y36680D01*
X4431029Y-2380995D01* G01X28310Y34730D01*
X3887470Y-5050027D02* G01X28310Y34730D01*
G01* G01X31999Y38450D02*
X3887470Y-4987543D01* G01X33179Y37270D01*
X4625086Y-4249927D01* G01X36689Y37270D01*
X4625086Y-2724912D01* G01X12999Y28310D02*
X4534915Y-2634995D01* G01X12999Y25549D01*
X4431029Y-2634995D01* G01X24349Y14200D01*
X5950000Y-4387517D02* G01X12999Y36729D02*
G01* G01X12999Y28308D01*
X5950000Y-4375000D01* G01X36689Y34730D02*
X5800001Y-4225000D01* G01X33030Y34730D01*
X5149999Y-4225000D01* G01X33000Y34700D01*
X4874999Y-3949999D01* G01X15450Y13381D02*
X4874999Y-2350000D01* G01X23530Y13381D01*
X4651994Y-2126995D01* G01X24350Y14199D01*
X4431004Y-2126995D01* G54D13*
X5949950Y-3487420D02* G01X20690Y44890D03*
G01* G01X20690Y42350D03*
X5949950Y-3474974D01* G01X20690Y34730D03*
X5875020Y-3400043D01* G01X20690Y32190D03*
X5150104Y-3400043D01* G01X20690Y39810D03*
X5025001Y-3274999D01* G01X20690Y37270D03*
X5025001Y-2200000D01* G01X20690Y29650D03*
X4697984Y-1872995D01* G01X20690Y27110D03*
X4431029Y-1872995D01* G01X28310Y27110D03*
X836929Y-223012D02* G01X28310Y29650D03*
G01* G01X28310Y32190D03*
X963929Y-350012D01* G01X28310Y34730D03*
X1167498Y-349999D01* G01X28310Y37270D03*
X1217498Y-399999D01* G01X28310Y39810D03*
X1217498Y-712497D01* G01X28310Y42350D03*
X1299972Y-785876D01* G01X28310Y44890D03*
X1299972Y-896873D01* G01X44310Y27110D03*
D13* G01X44310Y29650D03*
G01* G01X44310Y37270D03*
X2069007Y-1110995D03* G01X44310Y39810D03*
G01* G01X44310Y32190D03*
X2069007Y-1364995D03* G01X44310Y34730D03*
G01* G01X44310Y42350D03*
X2069007Y-2126995D03* G01X44310Y44890D03*
G01* G01X36690Y44890D03*
X2069007Y-2380995D03* G01X36690Y42350D03*
G01* G01X36690Y39810D03*
X2069007Y-1618995D03* G01X36690Y37270D03*
G01* G01X36690Y34730D03*
X2069007Y-1872995D03* G01X36690Y32190D03*
G01* G01X36690Y29650D03*
X2069007Y-2634995D03* G01X36690Y27110D03*
G01*
X2069007Y-2888995D03*
G01*
X2831007Y-2888995D03*
G01*
X2831007Y-2634995D03*
G01*
X2831007Y-2380995D03*
G01*
X2831007Y-2126995D03*
G01*
X2831007Y-1872995D03*
G01*
X2831007Y-1618995D03*
G01*
X2831007Y-1364995D03*
G01*
X2831007Y-1110995D03*
G01*
X4431004Y-2888995D03*
G01*
X4431004Y-2634995D03*
G01*
X4431004Y-1872995D03*
G01*
X4431004Y-1618995D03*
G01*
X4431004Y-2380995D03*
G01*
X4431004Y-2126995D03*
G01*
X4431004Y-1364995D03*
G01*
X4431004Y-1110995D03*
G01*
X3669004Y-1110995D03*
G01*
X3669004Y-1364995D03*
G01*
X3669004Y-1618995D03*
G01*
X3669004Y-1872995D03*
G01*
X3669004Y-2126995D03*
G01*
X3669004Y-2380995D03*
G01*
X3669004Y-2634995D03*
G01*
X3669004Y-2888995D03*
D14*
G01*
X4999939Y-3699992D03*
G01*
X5150053Y-3699992D03*
D15*
G01*
X1299997Y-1926996D03*
G01*
X1299997Y-896975D03*
G01*
X5253990Y-2861005D03*
G01*
X5253990Y-1830984D03*
G01*
X4224985Y-3210001D03*
G01*
X5255006Y-3210001D03*
G01*
X1299997Y-3799001D03*
G01*
X1299997Y-2768980D03*
D14*
G01*
X1394942Y-4261993D03*
G01*
X1545056Y-4261993D03*
D15*
G01*
X3960012Y-4345025D03*
G01*
X3960012Y-3314979D03*
G01*
X2434996Y-4180001D03*
G01*
X3465017Y-4180001D03*
G36* G36*
X5752998Y-386999D02* G01X57529Y52130D02*
G01* G01X55729Y52130D01*
X5572998Y-386999D01* G01X55729Y50330D01*
X5572998Y-566999D01* G01X57529Y50330D01*
X5752998Y-566999D01* G01X57529Y52130D01*
G37* G37*
D16* G54D14*
G01* G01X56630Y53769D03*
X5663006Y-223012D03* G01X54090Y51229D03*
G01* G01X54090Y53769D03*
X5409006Y-477012D03* G01X51550Y51229D03*
G01* G01X51550Y53769D03*
X5409006Y-223012D03* G01X49010Y51229D03*
G01* G01X49010Y53769D03*
X5155006Y-477012D03* G01X46470Y51229D03*
G01* G01X46470Y53769D03*
X5155006Y-223012D03* G01X43930Y51229D03*
G01* G01X43930Y53769D03*
X4901006Y-477012D03* G01X41390Y51229D03*
G01* G01X41390Y53769D03*
X4901006Y-223012D03* G01X38850Y51229D03*
G01* G01X38850Y53769D03*
X4647006Y-477012D03* G01X36310Y51229D03*
G01* G01X36310Y53769D03*
X4647006Y-223012D03* G01X33770Y51229D03*
G01* G01X33770Y53769D03*
X4393006Y-477012D03* G01X31230Y51229D03*
G01* G01X31230Y53769D03*
X4393006Y-223012D03* G01X28690Y51229D03*
G01* G01X28690Y53769D03*
X4139006Y-477012D03* G01X26150Y51229D03*
G01* G01X26150Y53769D03*
X4139006Y-223012D03* G01X23610Y51229D03*
G01* G01X23610Y53769D03*
X3885006Y-477012D03* G01X21070Y51229D03*
G01* G01X21070Y53769D03*
X3885006Y-223012D03* G01X18530Y51229D03*
G01* G01X18530Y53769D03*
X3631006Y-477012D03* G01X15990Y51229D03*
G01* G01X15990Y53769D03*
X3631006Y-223012D03* G01X13450Y51229D03*
G01* G01X13450Y53769D03*
X3377006Y-477012D03* G01X10910Y51229D03*
G01* G01X10910Y53769D03*
X3377006Y-223012D03* G01X8370Y51229D03*
G01* G01X8370Y53769D03*
X3123006Y-477012D03* G54D15*
G01* G01X49999Y19000D03*
X3123006Y-223012D03* G01X51500Y19000D03*
G01* G54D16*
X2869006Y-477012D03* G01X12999Y36730D03*
G01* G01X12999Y47030D03*
X2869006Y-223012D03* G01X52539Y27390D03*
G01* G01X52539Y37690D03*
X2615006Y-477012D03* G01X42249Y23900D03*
G01* G01X52550Y23900D03*
X2615006Y-223012D03* G01X12999Y18010D03*
G01* G01X12999Y28310D03*
X2361006Y-477012D03* G54D15*
G01* G01X13949Y13380D03*
X2361006Y-223012D03* G01X15450Y13380D03*
G01* G54D16*
X2107006Y-477012D03* G01X39600Y12549D03*
G01* G01X39600Y22850D03*
X2107006Y-223012D03* G01X24349Y14200D03*
G01* G01X34650Y14200D03*
X1853006Y-477012D03* G54D12*
G01* G01X31219Y39820D03*
X1853006Y-223012D03* G01X32999Y34700D03*
G01* G01X31999Y38450D03*
X1599006Y-477012D03* G01X30500Y38452D03*
G01* G01X36699Y25000D03*
X1599006Y-223012D03* G54D17*
G01* G01X32050Y22424D02*
X1345006Y-477012D03* G01X32950Y22424D01*
G01* G01X28600Y21225D02*
X1345006Y-223012D03* G01X28600Y22125D01*
G01* G01X30000Y18624D02*
X1091006Y-477012D03* G01X30000Y17724D01*
G01* G01X35000Y18624D02*
X1091006Y-223012D03* G01X35000Y17724D01*
G01* G01X36399Y22125D02*
X837006Y-477012D03* G01X36399Y21225D01*
G01* G01X5050Y48124D02*
X837006Y-223012D03* G01X5950Y48124D01*
D12* G01X1600Y46924D02*
G01* G01X1600Y47824D01*
X3121990Y-1618005D03* G01X3000Y44324D02*
G01* G01X3000Y43424D01*
X3299993Y-2129993D03* G01X8000Y44324D02*
G01* G01X8000Y43424D01*
X3199993Y-1754987D03* G01X9400Y47824D02*
G01* G01X9400Y46924D01*
X3050006Y-1754733D03* G01X5050Y39124D02*
G01* G01X5950Y39124D01*
X3669995Y-3099993D03* G01X1600Y37924D02*
D17* G01X1600Y38824D01*
X3205007Y-3357524D02* G01X3000Y35324D02*
G01* G01X3000Y34424D01*
X3295007Y-3357524D01* G01X8000Y35324D02*
X2860014Y-3477503D02* G01X8000Y34424D01*
G01* G01X9400Y38824D02*
X2860014Y-3387506D01* G01X9400Y37924D01*
X3000019Y-3737518D02* G01X5050Y30124D02*
G01* G01X5950Y30124D01*
X3000019Y-3827515D01* G01X1600Y28925D02*
X3500018Y-3737518D02* G01X1600Y29825D01*
G01* G01X3000Y26324D02*
X3500018Y-3827515D01* G01X3000Y25424D01*
X3639997Y-3387506D02* G01X8000Y26324D02*
G01* G01X8000Y25424D01*
X3639997Y-3477503D01* G01X9400Y29825D02*
X505012Y-787527D02* G01X9400Y28925D01*
G01* G01X5050Y21124D02*
X595012Y-787527D01* G01X5950Y21124D01*
X160020Y-907508D02* G01X1600Y19925D02*
G01* G01X1600Y20825D01*
X160020Y-817509D01* G01X3000Y17324D02*
X300024Y-1167521D02* G01X3000Y16424D01*
G01* G01X8000Y17324D02*
X300024Y-1257520D01* G01X8000Y16424D01*
X800023Y-1167521D02* G01X9400Y20825D02*
G01* G01X9400Y19925D01*
X800023Y-1257520D01* G01X5050Y12124D02*
X940003Y-817509D02* G01X5950Y12124D01*
G01* G01X1600Y10925D02*
X940003Y-907508D01* G01X1600Y11825D01*
X505012Y-1687525D02* G01X3000Y8324D02*
G01* G01X3000Y7424D01*
X595012Y-1687525D01* G01X8000Y8324D02*
X160020Y-1807507D02* G01X8000Y7424D01*
G01* G01X9400Y11825D02*
X160020Y-1717507D01* G01X9400Y10925D01*
X300024Y-2067519D02* G01X59050Y48124D02*
G01* G01X59950Y48124D01*
X300024Y-2157519D01* G01X55600Y46924D02*
X800023Y-2067519D02* G01X55600Y47824D01*
G01* G01X57000Y44324D02*
X800023Y-2157519D01* G01X57000Y43424D01*
X940003Y-1717507D02* G01X62000Y44324D02*
G01* G01X62000Y43424D01*
X940003Y-1807507D01* G01X63399Y47824D02*
X505012Y-2587523D02* G01X63399Y46924D01*
G01* G01X59050Y39124D02*
X595012Y-2587523D01* G01X59950Y39124D01*
X160020Y-2707505D02* G01X55600Y37924D02*
G01* G01X55600Y38824D01*
X160020Y-2617505D01* G01X57000Y35324D02*
X300024Y-2967517D02* G01X57000Y34424D01*
G01* G01X62000Y35324D02*
X300024Y-3057517D01* G01X62000Y34424D01*
X800023Y-2967517D02* G01X63399Y38824D02*
G01* G01X63399Y37924D01*
X800023Y-3057517D01* G01X59050Y30124D02*
X940003Y-2617505D02* G01X59950Y30124D01*
G01* G01X55600Y28925D02*
X940003Y-2707505D01* G01X55600Y29825D01*
X505012Y-3487521D02* G01X57000Y26324D02*
G01* G01X57000Y25424D01*
X595012Y-3487521D01* G01X62000Y26324D02*
X160020Y-3607503D02* G01X62000Y25424D01*
G01* G01X63399Y29825D02*
X160020Y-3517503D01* G01X63399Y28925D01*
X300024Y-3867515D02* G01X59050Y21124D02*
G01* G01X59950Y21124D01*
X300024Y-3957515D01* G01X55600Y19925D02*
X800023Y-3867515D02* G01X55600Y20825D01*
G01* G01X57000Y17324D02*
X800023Y-3957515D01* G01X57000Y16424D01*
X940003Y-3517503D02* G01X62000Y17324D02*
G01* G01X62000Y16424D01*
X940003Y-3607503D01* G01X63399Y20825D02*
X505012Y-4387519D02* G01X63399Y19925D01*
G01* G01X59050Y12124D02*
X595012Y-4387519D01* G01X59950Y12124D01*
X160020Y-4507501D02* G01X55600Y10925D02*
G01* G01X55600Y11825D01*
X160020Y-4417501D01* G01X57000Y8324D02*
X300024Y-4767513D02* G01X57000Y7424D01*
G01* G01X62000Y8324D02*
X300024Y-4857513D01* G01X62000Y7424D01*
X800023Y-4767513D02* G01X63399Y11825D02*
G01* G01X63399Y10925D01*
X800023Y-4857513D01* G01X11875Y5050D02*
X940003Y-4417501D02* G01X11875Y5950D01*
G01* G01X13075Y1600D02*
X940003Y-4507501D01* G01X12175Y1600D01*
X5905002Y-787527D02* G01X15675Y3000D02*
G01* G01X16575Y3000D01*
X5995001Y-787527D01* G01X15675Y8000D02*
X5560009Y-907508D02* G01X16575Y8000D01*
G01* G01X12175Y9399D02*
X5560009Y-817509D01* G01X13075Y9399D01*
X5700013Y-1167521D02* G01X20875Y5050D02*
G01* G01X20875Y5950D01*
X5700013Y-1257520D01* G01X22075Y1600D02*
X6200013Y-1167521D02* G01X21175Y1600D01*
G01* G01X24675Y3000D02*
X6200013Y-1257520D01* G01X25575Y3000D01*
X6339992Y-817509D02* G01X24675Y8000D02*
G01* G01X25575Y8000D01*
X6339992Y-907508D01* G01X21175Y9399D02*
X5905002Y-1687525D02* G01X22075Y9399D01*
G01* G01X29875Y5050D02*
X5995001Y-1687525D01* G01X29875Y5950D01*
X5560009Y-1807507D02* G01X31075Y1600D02*
G01* G01X30175Y1600D01*
X5560009Y-1717507D01* G01X33675Y3000D02*
X5700013Y-2067519D02* G01X34575Y3000D01*
G01* G01X33675Y8000D02*
X5700013Y-2157519D01* G01X34575Y8000D01*
X6200013Y-2067519D02* G01X30175Y9399D02*
G01* G01X31075Y9399D01*
X6200013Y-2157519D01* G01X38875Y5050D02*
X6339992Y-1717507D02* G01X38875Y5950D01*
G01* G01X40075Y1600D02*
X6339992Y-1807507D01* G01X39175Y1600D01*
X5905002Y-2587523D02* G01X42675Y3000D02*
G01* G01X43575Y3000D01*
X5995001Y-2587523D01* G01X42675Y8000D02*
X5560009Y-2707505D02* G01X43575Y8000D01*
G01* G01X39175Y9399D02*
X5560009Y-2617505D01* G01X40075Y9399D01*
X5700013Y-2967517D02* G01X47875Y5050D02*
G01* G01X47875Y5950D01*
X5700013Y-3057517D01* G01X49074Y1600D02*
X6200013Y-2967517D02* G01X48175Y1600D01*
G01* G01X51675Y3000D02*
X6200013Y-3057517D01* G01X52575Y3000D01*
X6339992Y-2617505D02* G01X51675Y8000D02*
G01* G01X52575Y8000D01*
X6339992Y-2707505D01* G01X48175Y9399D02*
X5905002Y-3487521D02* G01X49074Y9399D01*
G01* M00*
X5995001Y-3487521D01*
X5560009Y-3607503D02*
G01*
X5560009Y-3517503D01*
X5700013Y-3867515D02*
G01*
X5700013Y-3957515D01*
X6200013Y-3867515D02*
G01*
X6200013Y-3957515D01*
X6339992Y-3517503D02*
G01*
X6339992Y-3607503D01*
X5905002Y-4387519D02*
G01*
X5995001Y-4387519D01*
X5560009Y-4507501D02*
G01*
X5560009Y-4417501D01*
X5700013Y-4767513D02*
G01*
X5700013Y-4857513D01*
X6200013Y-4767513D02*
G01*
X6200013Y-4857513D01*
X6339992Y-4417501D02*
G01*
X6339992Y-4507501D01*
X1187526Y-5095003D02*
G01*
X1187526Y-5005003D01*
X1307505Y-5439994D02*
G01*
X1217508Y-5439994D01*
X1567520Y-5299989D02*
G01*
X1657517Y-5299989D01*
X1567520Y-4799990D02*
G01*
X1657517Y-4799990D01*
X1217508Y-4660011D02*
G01*
X1307505Y-4660011D01*
X2087524Y-5095003D02*
G01*
X2087524Y-5005003D01*
X2207503Y-5439994D02*
G01*
X2117506Y-5439994D01*
X2467518Y-5299989D02*
G01*
X2557515Y-5299989D01*
X2467518Y-4799990D02*
G01*
X2557515Y-4799990D01*
X2117506Y-4660011D02*
G01*
X2207503Y-4660011D01*
X2987522Y-5095003D02*
G01*
X2987522Y-5005003D01*
X3107502Y-5439994D02*
G01*
X3017504Y-5439994D01*
X3367516Y-5299989D02*
G01*
X3457514Y-5299989D01*
X3367516Y-4799990D02*
G01*
X3457514Y-4799990D01*
X3017504Y-4660011D02*
G01*
X3107502Y-4660011D01*
X3887520Y-5095003D02*
G01*
X3887520Y-5005003D01*
X4007500Y-5439994D02*
G01*
X3917502Y-5439994D01*
X4267514Y-5299989D02*
G01*
X4357512Y-5299989D01*
X4267514Y-4799990D02*
G01*
X4357512Y-4799990D01*
X3917502Y-4660011D02*
G01*
X4007500Y-4660011D01*
X4787518Y-5095003D02*
G01*
X4787518Y-5005003D01*
X4907498Y-5439994D02*
G01*
X4817501Y-5439994D01*
X5167513Y-5299989D02*
G01*
X5257510Y-5299989D01*
X5167513Y-4799990D02*
G01*
X5257510Y-4799990D01*
X4817501Y-4660011D02*
G01*
X4907498Y-4660011D01*
M02* M02*

View File

@ -1,88 +1,84 @@
G04 Layer: BottomSilkLayer* G04 Layer: BottomSilkLayer*
G04 EasyEDA v6.4.25, 2022-04-08T13:20:52--5:00* G04 EasyEDA v6.4.0, 2020-07-14T23:16:01--5:00*
G04 6dc5d916f8a9456ea10d5ff2c879efc5,9df6f537d2f94b3ba0ed850023b5714d,10*
G04 Gerber Generator version 0.2* G04 Gerber Generator version 0.2*
G04 Scale: 100 percent, Rotated: No, Reflected: No * G04 Scale: 100 percent, Rotated: No, Reflected: No *
G04 Dimensions in millimeters * G04 Dimensions in millimeters *
G04 leading zeros omitted , absolute positions ,4 integer and 5 decimal * G04 leading zeros omitted , absolute positions ,3 integer and 3 decimal *
%FSLAX45Y45*% %FSLAX33Y33*%
%MOMM*% %MOMM*%
G90*
G71D02*
%ADD10C,0.2540*% %ADD10C,0.254000*%
%ADD18C,0.1524*% %ADD18C,0.152400*%
%LPD*% %LPD*%
D18* G54D10*
X2956062Y-674636D02* G01X57899Y49960D02*
G01* G01X57899Y55040D01*
X2961259Y-664245D01* G01X7099Y55040D01*
X2971650Y-653854D01* G01X7099Y49960D01*
X2982038Y-648660D01* G01X57899Y49960D01*
X3002821Y-648660D01* G01X57899Y52500D02*
X3013212Y-653854D01* G01X55359Y52500D01*
X3023603Y-664245D01* G01X55359Y49960D01*
X3028800Y-674636D01* G54D18*
X3033994Y-690224D01* G01X29560Y49253D02*
X3033994Y-716201D01* G01X29612Y49357D01*
X3028800Y-731786D01* G01X29716Y49461D01*
X3023603Y-742177D01* G01X29820Y49513D01*
X3013212Y-752568D01* G01X30028Y49513D01*
X3002821Y-757763D01* G01X30132Y49461D01*
X2982038Y-757763D01* G01X30236Y49357D01*
X2971650Y-752568D01* G01X30288Y49253D01*
X2961259Y-742177D01* G01X30339Y49097D01*
X2956062Y-731786D01* G01X30339Y48838D01*
X2956062Y-716201D01* G01X30288Y48682D01*
X2982038Y-716201D02* G01X30236Y48578D01*
G01* G01X30132Y48474D01*
X2956062Y-716201D01* G01X30028Y48422D01*
X2921772Y-648660D02* G01X29820Y48422D01*
G01* G01X29716Y48474D01*
X2921772Y-757763D01* G01X29612Y48578D01*
X2921772Y-648660D02* G01X29560Y48682D01*
G01* G01X29560Y48838D01*
X2875013Y-648660D01* G01X29820Y48838D02*
X2859427Y-653854D01* G01X29560Y48838D01*
X2854231Y-659051D01* G01X29217Y49513D02*
X2849036Y-669442D01* G01X29217Y48422D01*
X2849036Y-685027D01* G01X29217Y49513D02*
X2854231Y-695418D01* G01X28750Y49513D01*
X2859427Y-700613D01* G01X28594Y49461D01*
X2875013Y-705810D01* G01X28542Y49409D01*
X2921772Y-705810D01* G01X28490Y49305D01*
X2814746Y-648660D02* G01X28490Y49149D01*
G01* G01X28542Y49045D01*
X2814746Y-757763D01* G01X28594Y48993D01*
X2749283Y-648660D02* G01X28750Y48941D01*
G01* G01X29217Y48941D01*
X2759674Y-653854D01* G01X28147Y49513D02*
X2770065Y-664245D01* G01X28147Y48422D01*
X2775259Y-674636D01* G01X27492Y49513D02*
X2780456Y-690224D01* G01X27596Y49461D01*
X2780456Y-716201D01* G01X27700Y49357D01*
X2775259Y-731786D01* G01X27752Y49253D01*
X2770065Y-742177D01* G01X27804Y49097D01*
X2759674Y-752568D01* G01X27804Y48838D01*
X2749283Y-757763D01* G01X27752Y48682D01*
X2728501Y-757763D01* G01X27700Y48578D01*
X2718109Y-752568D01* G01X27596Y48474D01*
X2707718Y-742177D01* G01X27492Y48422D01*
X2702524Y-731786D01* G01X27285Y48422D01*
X2697330Y-716201D01* G01X27181Y48474D01*
X2697330Y-690224D01* G01X27077Y48578D01*
X2702524Y-674636D01* G01X27025Y48682D01*
X2707718Y-664245D01* G01X26973Y48838D01*
X2718109Y-653854D01* G01X26973Y49097D01*
X2728501Y-648660D01* G01X27025Y49253D01*
X2749283Y-648660D01* G01X27077Y49357D01*
D10* G01X27181Y49461D01*
X5789998Y-603999D02* G01X27285Y49513D01*
G01* G01X27492Y49513D01*
X5789998Y-95999D01* M00*
X709998Y-95999D01*
X709998Y-603999D01*
X5789998Y-603999D01*
X5789998Y-349999D02*
G01*
X5535998Y-349999D01*
X5535998Y-603999D01*
M02* M02*

File diff suppressed because it is too large Load Diff

View File

@ -1,38 +1,36 @@
;Layer: Drill NPTH
;EasyEDA v6.4.0, 2020-07-14T23:16:01--5:00
;6dc5d916f8a9456ea10d5ff2c879efc5,9df6f537d2f94b3ba0ed850023b5714d,10
;Gerber Generator version 0.2
M48 M48
METRIC,LZ,000.000 METRIC,LZ,000.000
;FILE_FORMAT=3:3 ;Holesize 1 = 1.301 METRIC
;TYPE=NON_PLATED
;Layer: Drill NPTH
;EasyEDA v6.4.25, 2022-04-08T13:20:52--5:00
;10
;Gerber Generator version 0.2
;Holesize 1 = 1.301 mm
T01C1.301 T01C1.301
;Holesize 2 = 2.751 mm ;Holesize 2 = 2.751 METRIC
T02C2.751 T02C2.751
% %
G05 G05
G90 G90
T01 T01
X032500Y-038575 X+032500Y+017424
X005500Y-012875 X+005500Y+043124
X005500Y-021875 X+005500Y+034124
X005500Y-030875 X+005500Y+025124
X005500Y-039875 X+005500Y+016124
X005500Y-048875 X+005500Y+007124
X059500Y-012875 X+059500Y+043124
X059500Y-021875 X+059500Y+034124
X059500Y-030875 X+059500Y+025124
X059500Y-039875 X+059500Y+016124
X059500Y-048875 X+059500Y+007124
X016875Y-050500 X+016875Y+005500
X025875Y-050500 X+025875Y+005500
X034875Y-050500 X+034875Y+005500
X043875Y-050500 X+043875Y+005500
X052875Y-050500 X+052875Y+005500
T02 T02
X061500Y-003500 X+061500Y+052499
X061500Y-052500 X+061500Y+003500
X003500Y-003500 X+003500Y+052499
X003500Y-052500 X+003500Y+003500
M30 M30

View File

@ -1,200 +1,198 @@
;Layer: Drill PTH
;EasyEDA v6.4.0, 2020-07-14T23:16:01--5:00
;6dc5d916f8a9456ea10d5ff2c879efc5,9df6f537d2f94b3ba0ed850023b5714d,10
;Gerber Generator version 0.2
M48 M48
METRIC,LZ,000.000 METRIC,LZ,000.000
;FILE_FORMAT=3:3 ;Holesize 1 = 0.305 METRIC
;TYPE=PLATED
;Layer: Drill PTH
;EasyEDA v6.4.25, 2022-04-08T13:20:52--5:00
;10
;Gerber Generator version 0.2
;Holesize 1 = 0.305 mm
T01C0.305 T01C0.305
;Holesize 2 = 0.800 mm ;Holesize 2 = 0.800 METRIC
T02C0.800 T02C0.800
;Holesize 3 = 1.000 mm ;Holesize 3 = 1.000 METRIC
T03C1.000 T03C1.000
;Holesize 4 = 1.101 mm ;Holesize 4 = 1.101 METRIC
T04C1.101 T04C1.101
;Holesize 5 = 1.200 mm ;Holesize 5 = 1.200 METRIC
T05C1.200 T05C1.200
% %
G05 G05
G90 G90
T01 T01
X031220Y-016180 X+031219Y+039820
X033000Y-021300 X+032999Y+034700
X032000Y-017550 X+031999Y+038450
X030500Y-017547 X+030500Y+038452
X036700Y-031000 X+036699Y+025000
T02 T02
X032950Y-033575G85X032050Y-033575 X+032950Y+022425G85X+032049Y+022425
X028600Y-033875G85X028600Y-034775 X+028600Y+022125G85X+028600Y+021225
X030000Y-038275G85X030000Y-037375 X+030000Y+017725G85X+030000Y+018625
X035000Y-038275G85X035000Y-037375 X+035000Y+017725G85X+035000Y+018625
X036400Y-034775G85X036400Y-033875 X+036400Y+021225G85X+036400Y+022125
X049999Y-037000 X+049999Y+019000
X051501Y-037000 X+051500Y+019000
X013949Y-042620 X+013949Y+013380
X015451Y-042620 X+015450Y+013380
X005950Y-007875G85X005050Y-007875 X+005950Y+048125G85X+005049Y+048125
X001600Y-008175G85X001600Y-009075 X+001599Y+047825G85X+001599Y+046925
X003000Y-012575G85X003000Y-011675 X+002999Y+043425G85X+002999Y+044325
X008000Y-012575G85X008000Y-011675 X+007999Y+043425G85X+007999Y+044325
X009400Y-009075G85X009400Y-008175 X+009399Y+046925G85X+009399Y+047825
X005950Y-016875G85X005050Y-016875 X+005950Y+039125G85X+005049Y+039125
X001600Y-017175G85X001600Y-018075 X+001599Y+038825G85X+001599Y+037925
X003000Y-021575G85X003000Y-020675 X+002999Y+034425G85X+002999Y+035325
X008000Y-021575G85X008000Y-020675 X+007999Y+034425G85X+007999Y+035325
X009400Y-018075G85X009400Y-017175 X+009399Y+037925G85X+009399Y+038825
X005950Y-025875G85X005050Y-025875 X+005950Y+030125G85X+005049Y+030125
X001600Y-026175G85X001600Y-027075 X+001599Y+029825G85X+001599Y+028925
X003000Y-030575G85X003000Y-029675 X+002999Y+025425G85X+002999Y+026325
X008000Y-030575G85X008000Y-029675 X+007999Y+025425G85X+007999Y+026325
X009400Y-027075G85X009400Y-026175 X+009399Y+028925G85X+009399Y+029825
X005950Y-034875G85X005050Y-034875 X+005950Y+021125G85X+005049Y+021125
X001600Y-035175G85X001600Y-036075 X+001599Y+020825G85X+001599Y+019925
X003000Y-039575G85X003000Y-038675 X+002999Y+016425G85X+002999Y+017325
X008000Y-039575G85X008000Y-038675 X+007999Y+016425G85X+007999Y+017325
X009400Y-036075G85X009400Y-035175 X+009399Y+019925G85X+009399Y+020825
X005950Y-043875G85X005050Y-043875 X+005950Y+012125G85X+005049Y+012125
X001600Y-044175G85X001600Y-045075 X+001599Y+011825G85X+001599Y+010925
X003000Y-048575G85X003000Y-047675 X+002999Y+007425G85X+002999Y+008325
X008000Y-048575G85X008000Y-047675 X+007999Y+007425G85X+007999Y+008325
X009400Y-045075G85X009400Y-044175 X+009399Y+010925G85X+009399Y+011825
X059950Y-007875G85X059050Y-007875 X+059950Y+048125G85X+059049Y+048125
X055600Y-008175G85X055600Y-009075 X+055600Y+047825G85X+055600Y+046925
X057000Y-012575G85X057000Y-011675 X+057000Y+043425G85X+057000Y+044325
X062000Y-012575G85X062000Y-011675 X+062000Y+043425G85X+062000Y+044325
X063400Y-009075G85X063400Y-008175 X+063400Y+046925G85X+063400Y+047825
X059950Y-016875G85X059050Y-016875 X+059950Y+039125G85X+059049Y+039125
X055600Y-017175G85X055600Y-018075 X+055600Y+038825G85X+055600Y+037925
X057000Y-021575G85X057000Y-020675 X+057000Y+034425G85X+057000Y+035325
X062000Y-021575G85X062000Y-020675 X+062000Y+034425G85X+062000Y+035325
X063400Y-018075G85X063400Y-017175 X+063400Y+037925G85X+063400Y+038825
X059950Y-025875G85X059050Y-025875 X+059950Y+030125G85X+059049Y+030125
X055600Y-026175G85X055600Y-027075 X+055600Y+029825G85X+055600Y+028925
X057000Y-030575G85X057000Y-029675 X+057000Y+025425G85X+057000Y+026325
X062000Y-030575G85X062000Y-029675 X+062000Y+025425G85X+062000Y+026325
X063400Y-027075G85X063400Y-026175 X+063400Y+028925G85X+063400Y+029825
X059950Y-034875G85X059050Y-034875 X+059950Y+021125G85X+059049Y+021125
X055600Y-035175G85X055600Y-036075 X+055600Y+020825G85X+055600Y+019925
X057000Y-039575G85X057000Y-038675 X+057000Y+016425G85X+057000Y+017325
X062000Y-039575G85X062000Y-038675 X+062000Y+016425G85X+062000Y+017325
X063400Y-036075G85X063400Y-035175 X+063400Y+019925G85X+063400Y+020825
X059950Y-043875G85X059050Y-043875 X+059950Y+012125G85X+059049Y+012125
X055600Y-044175G85X055600Y-045075 X+055600Y+011825G85X+055600Y+010925
X057000Y-048575G85X057000Y-047675 X+057000Y+007425G85X+057000Y+008325
X062000Y-048575G85X062000Y-047675 X+062000Y+007425G85X+062000Y+008325
X063400Y-045075G85X063400Y-044175 X+063400Y+010925G85X+063400Y+011825
X011875Y-050050G85X011875Y-050950 X+011874Y+005950G85X+011874Y+005050
X012175Y-054400G85X013075Y-054400 X+012174Y+001600G85X+013074Y+001600
X016575Y-053000G85X015675Y-053000 X+016574Y+003000G85X+015674Y+003000
X016575Y-048000G85X015675Y-048000 X+016574Y+008000G85X+015674Y+008000
X013075Y-046600G85X012175Y-046600 X+013074Y+009400G85X+012174Y+009400
X020875Y-050050G85X020875Y-050950 X+020874Y+005950G85X+020874Y+005050
X021175Y-054400G85X022075Y-054400 X+021174Y+001600G85X+022074Y+001600
X025575Y-053000G85X024675Y-053000 X+025575Y+003000G85X+024674Y+003000
X025575Y-048000G85X024675Y-048000 X+025575Y+008000G85X+024674Y+008000
X022075Y-046600G85X021175Y-046600 X+022074Y+009400G85X+021174Y+009400
X029875Y-050050G85X029875Y-050950 X+029874Y+005950G85X+029874Y+005050
X030175Y-054400G85X031075Y-054400 X+030174Y+001600G85X+031074Y+001600
X034575Y-053000G85X033675Y-053000 X+034575Y+003000G85X+033674Y+003000
X034575Y-048000G85X033675Y-048000 X+034575Y+008000G85X+033674Y+008000
X031075Y-046600G85X030175Y-046600 X+031074Y+009400G85X+030174Y+009400
X038875Y-050050G85X038875Y-050950 X+038874Y+005950G85X+038874Y+005050
X039175Y-054400G85X040075Y-054400 X+039174Y+001600G85X+040074Y+001600
X043575Y-053000G85X042675Y-053000 X+043574Y+003000G85X+042674Y+003000
X043575Y-048000G85X042675Y-048000 X+043574Y+008000G85X+042674Y+008000
X040075Y-046600G85X039175Y-046600 X+040074Y+009400G85X+039174Y+009400
X047875Y-050050G85X047875Y-050950 X+047874Y+005950G85X+047874Y+005050
X048175Y-054400G85X049075Y-054400 X+048174Y+001600G85X+049074Y+001600
X052575Y-053000G85X051675Y-053000 X+052575Y+003000G85X+051674Y+003000
X052575Y-048000G85X051675Y-048000 X+052575Y+008000G85X+051674Y+008000
X049075Y-046600G85X048175Y-046600 X+049074Y+009400G85X+048174Y+009400
T03 T03
X013000Y-019270 X+012999Y+036730
X013000Y-008970 X+012999Y+047030
X052540Y-028610 X+052539Y+027390
X052540Y-018310 X+052539Y+037690
X042250Y-032100 X+042250Y+023900
X052550Y-032100 X+052550Y+023900
X013000Y-037990 X+012999Y+018010
X013000Y-027690 X+012999Y+028310
X039600Y-043450 X+039600Y+012550
X039600Y-033150 X+039600Y+022850
X024350Y-041800 X+024350Y+014200
X034650Y-041800 X+034650Y+014200
T04 T04
X020690Y-011110 X+020690Y+044890
X020690Y-013650 X+020690Y+042350
X020690Y-021270 X+020690Y+034730
X020690Y-023810 X+020690Y+032190
X020690Y-016190 X+020690Y+039810
X020690Y-018730 X+020690Y+037270
X020690Y-026350 X+020690Y+029650
X020690Y-028890 X+020690Y+027110
X028310Y-028890 X+028310Y+027110
X028310Y-026350 X+028310Y+029650
X028310Y-023810 X+028310Y+032190
X028310Y-021270 X+028310Y+034730
X028310Y-018730 X+028310Y+037270
X028310Y-016190 X+028310Y+039810
X028310Y-013650 X+028310Y+042350
X028310Y-011110 X+028310Y+044890
X044310Y-028890 X+044309Y+027110
X044310Y-026350 X+044309Y+029650
X044310Y-018730 X+044309Y+037270
X044310Y-016190 X+044309Y+039810
X044310Y-023810 X+044309Y+032190
X044310Y-021270 X+044309Y+034730
X044310Y-013650 X+044309Y+042350
X044310Y-011110 X+044309Y+044890
X036690Y-011110 X+036689Y+044890
X036690Y-013650 X+036689Y+042350
X036690Y-016190 X+036689Y+039810
X036690Y-018730 X+036689Y+037270
X036690Y-021270 X+036689Y+034730
X036690Y-023810 X+036689Y+032190
X036690Y-026350 X+036689Y+029650
X036690Y-028890 X+036689Y+027110
T05 T05
X056630Y-004770 X+056630Y+051230
X056630Y-002230 X+056630Y+053770
X054090Y-004770 X+054090Y+051230
X054090Y-002230 X+054090Y+053770
X051550Y-004770 X+051550Y+051230
X051550Y-002230 X+051550Y+053770
X049010Y-004770 X+049010Y+051230
X049010Y-002230 X+049010Y+053770
X046470Y-004770 X+046470Y+051230
X046470Y-002230 X+046470Y+053770
X043930Y-004770 X+043930Y+051230
X043930Y-002230 X+043930Y+053770
X041390Y-004770 X+041390Y+051230
X041390Y-002230 X+041390Y+053770
X038850Y-004770 X+038850Y+051230
X038850Y-002230 X+038850Y+053770
X036310Y-004770 X+036310Y+051230
X036310Y-002230 X+036310Y+053770
X033770Y-004770 X+033770Y+051230
X033770Y-002230 X+033770Y+053770
X031230Y-004770 X+031230Y+051230
X031230Y-002230 X+031230Y+053770
X028690Y-004770 X+028690Y+051230
X028690Y-002230 X+028690Y+053770
X026150Y-004770 X+026150Y+051230
X026150Y-002230 X+026150Y+053770
X023610Y-004770 X+023610Y+051230
X023610Y-002230 X+023610Y+053770
X021070Y-004770 X+021070Y+051230
X021070Y-002230 X+021070Y+053770
X018530Y-004770 X+018530Y+051230
X018530Y-002230 X+018530Y+053770
X015990Y-004770 X+015990Y+051230
X015990Y-002230 X+015990Y+053770
X013450Y-004770 X+013450Y+051230
X013450Y-002230 X+013450Y+053770
X010910Y-004770 X+010910Y+051230
X010910Y-002230 X+010910Y+053770
X008370Y-004770 X+008370Y+051230
X008370Y-002230 X+008370Y+053770
M30 M30

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -1,68 +0,0 @@
<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>
<artifactId>lantern-pigpio</artifactId>
<packaging>jar</packaging>
<version>1.0.0</version>
<name>lantern-pigpio</name>
<parent>
<groupId>com.lanternsoftware.pigpio</groupId>
<artifactId>pigpio</artifactId>
<version>1.0.0</version>
</parent>
<dependencies>
<dependency>
<groupId>com.lanternsoftware.util</groupId>
<artifactId>lantern-util-common</artifactId>
<version>${util.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.29</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.10.1</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>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -1,52 +0,0 @@
package com.lanternsoftware.pigpio;
import com.lanternsoftware.util.ResourceLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PIGPIO {
protected static final Logger LOG = LoggerFactory.getLogger(PIGPIO.class);
private PIGPIO() {
}
static {
try {
String osArch = System.getProperty("os.arch").toLowerCase();
if (osArch.equals("arm"))
osArch = "armhf";
String path = "/lib/" + osArch + "/lantern-pigpio.so";
byte[] file = ResourceLoader.getByteArrayResource(PIGPIO.class, path);
LOG.info("library size: {}", file.length);
String libPath = "/opt/currentmonitor/lantern-pigpio.so";
ResourceLoader.writeFile(libPath, file);
System.load(libPath);
} catch (Exception _e) {
LOG.error("Failed to load lantern-pigpio.so from resource", _e);
}
}
public static native int gpioInitialise();
public static native void gpioTerminate();
public static native int gpioSetMode(int gpio, int mode);
public static native int gpioGetMode(int gpio);
public static native int gpioSetPullUpDown(int gpio, int pud);
public static native int gpioRead(int gpio);
public static native int gpioWrite(int gpio, int level);
public static native int spiOpen(int spiChan, int baud, int spiFlags);
public static native int spiClose(int handle);
public static native int spiRead(int handle, byte[] buf, int offset, int count);
public static native int spiWrite(int handle, byte[] buf, int offset, int count);
public static native int spiXfer(int handle, byte[] txBuf, int txOffset, byte[] rxBuf, int rxOffset, int count);
}

View File

@ -1,53 +0,0 @@
package com.lanternsoftware.pigpio;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
public class PiGpioFactory {
private static final Logger LOG = LoggerFactory.getLogger(PIGPIO.class);
private static final Map<Integer, Spi> spiHandles = new HashMap<>();
private static boolean initialized = false;
public static Spi getSpiChannel(int _channel, int _baud, boolean _auxiliary) {
if (!ensureInitialized())
return null;
int channelId = (0xff & _channel);
if (_auxiliary)
channelId |= 0x100;
Spi handle = spiHandles.get(channelId);
if (handle != null)
return handle;
int h = PIGPIO.spiOpen(_channel, _baud, _auxiliary ? 0x100 : 0);
if (h >= 0) {
handle = new Spi(h);
spiHandles.put(channelId, handle);
return handle;
}
LOG.error("Failed to get SPI handle");
return null;
}
private static boolean ensureInitialized() {
if (initialized)
return true;
int init = PIGPIO.gpioInitialise();
LOG.info("GPIO init: {}", init);
if (init < 0) {
LOG.error("Failed to initialize PiGpio");
return false;
}
initialized = true;
return true;
}
public static void shutdown() {
for (Spi handle : spiHandles.values()) {
PIGPIO.spiClose(handle.getHandle());
}
spiHandles.clear();
PIGPIO.gpioTerminate();
}
}

View File

@ -1,37 +0,0 @@
package com.lanternsoftware.pigpio;
public class Spi {
private final int handle;
public Spi(int _handle) {
handle = _handle;
}
public int getHandle() {
return handle;
}
public int read(byte[] buf) {
return read(buf, 0, buf.length);
}
public int read(byte[] buf, int offset, int count) {
return PIGPIO.spiRead(handle, buf, offset, count);
}
public int write(byte[] buf) {
return write(buf, 0, buf.length);
}
public int write(byte[] buf, int offset, int count) {
return PIGPIO.spiWrite(handle, buf, offset, count);
}
public int transfer(byte[] txBuf, byte[] rxBuf) {
return transfer(txBuf, 0, rxBuf, 0, rxBuf.length);
}
public int transfer(byte[] txBuf, int txOffset, byte[] rxBuf, int rxOffset, int count) {
return PIGPIO.spiXfer(handle, txBuf, txOffset, rxBuf, rxOffset, count);
}
}

View File

@ -1,54 +0,0 @@
ARCH := armhf
DEBUG = -O3
CC = $(CROSS_PREFIX)gcc
AR = $(CROSS_PREFIX)ar
RANLIB = $(CROSS_PREFIX)ranlib
SIZE = $(CROSS_PREFIX)size
STRIP = $(CROSS_PREFIX)strip
SHLIB = $(CC) -shared
STRIPLIB = $(STRIP) --strip-unneeded
INCLUDE = -I. -Ipigpio \
-I/$(JAVA_HOME)/include \
-I/$(JAVA_HOME)/include/linux \
-I/usr/local/include -I/usr/local/include/linux
CFLAGS := $(DEBUG) -Wall $(INCLUDE) -Winline -pipe $(CARGS) -fPIC
LIBS = -L lib/$(ARCH) -L pigpio -lpigpio -lrt
TARGET=lantern-pigpio.so
###############################################################################
SRC = com_lanternsoftware_pigpio_PIGPIO.c
OBJ = $(SRC:.c=.o)
all: $(OBJ)
@echo [LINK with DYNAMICALLY linked libraries]
@$(CC) $(OBJ) -shared -o $(TARGET) $(INCLUDE) $(LIBS)
.c.o:
@echo [COMPILE] $<
@$(CC) -c $(CFLAGS) $< -o $@
clean:
rm -f $(OBJ) $(TARGET) *~ core tags Makefile.bak
tags: $(SRC)
@echo [ctags]
@ctags $(SRC)
depend:
makedepend -Y $(SRC)
install: $(TARGET)
@echo [install]
install -m 0755 -d /usr/local/lib
install -m 0755 -d /usr/local/include
install -m 0644 $(TARGET) /usr/local/lib
uninstall:
@echo [uninstall]
rm -f /usr/local/lib/$(TARGET)
com_lanternsoftware_pigpio_PIGPIO.o: com_lanternsoftware_pigpio_PIGPIO.h

View File

@ -1,117 +0,0 @@
#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
#include <pigpio.h>
#include "com_lanternsoftware_pigpio_PIGPIO.h"
JavaVM *callback_jvm;
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved)
{
JNIEnv *env;
if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_2))
{
return JNI_ERR;
}
callback_jvm = jvm;
return JNI_VERSION_1_2;
}
JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *jvm, void *reserved)
{
return;
}
JNIEXPORT jint JNICALL Java_com_lanternsoftware_pigpio_PIGPIO_gpioInitialise
(JNIEnv *env, jclass class)
{
gpioCfgSetInternals (gpioCfgGetInternals () | PI_CFG_NOSIGHANDLER);
return gpioInitialise();
}
JNIEXPORT void JNICALL Java_com_lanternsoftware_pigpio_PIGPIO_gpioTerminate(JNIEnv *env, jclass class)
{
return gpioTerminate();
}
JNIEXPORT jint JNICALL Java_com_lanternsoftware_pigpio_PIGPIO_gpioSetMode
(JNIEnv *env, jclass class, jint gpio, jint mode)
{
return gpioSetMode((unsigned)gpio, (unsigned)mode);
}
JNIEXPORT jint JNICALL Java_com_lanternsoftware_pigpio_PIGPIO_gpioGetMode
(JNIEnv *env, jclass class, jint gpio)
{
return gpioGetMode((unsigned)gpio);
}
JNIEXPORT jint JNICALL Java_com_lanternsoftware_pigpio_PIGPIO_gpioSetPullUpDown
(JNIEnv *env, jclass class, jint gpio, jint pud)
{
return gpioSetPullUpDown((unsigned)gpio, (unsigned)pud);
}
JNIEXPORT jint JNICALL Java_com_lanternsoftware_pigpio_PIGPIO_gpioRead
(JNIEnv *env, jclass class, jint gpio)
{
return gpioRead((unsigned)gpio);
}
JNIEXPORT jint JNICALL Java_com_lanternsoftware_pigpio_PIGPIO_gpioWrite
(JNIEnv *env, jclass class, jint gpio, jint level)
{
return gpioWrite((unsigned)gpio, (unsigned)level);
}
JNIEXPORT jint JNICALL Java_com_lanternsoftware_pigpio_PIGPIO_spiOpen
(JNIEnv *env, jclass class, jint spiChan, jint baud, jint spiFlags)
{
return spiOpen((unsigned)spiChan, (unsigned)baud, (unsigned)spiFlags);
}
JNIEXPORT jint JNICALL Java_com_lanternsoftware_pigpio_PIGPIO_spiClose
(JNIEnv *env, jclass class, jint handle)
{
return spiClose((unsigned)handle);
}
JNIEXPORT jint JNICALL Java_com_lanternsoftware_pigpio_PIGPIO_spiRead
(JNIEnv *env, jclass class, jint handle, jbyteArray data, jint offset, jint count)
{
jbyte *buffer = (*env)->GetByteArrayElements(env, data, 0);
jsize max_length = (*env)->GetArrayLength(env, data) - offset;
int length = (count > max_length) ? max_length : count;
jbyte *offsetBuffer = buffer + offset;
jint result = spiRead((unsigned)handle, (char *)offsetBuffer, (unsigned)length);
(*env)->ReleaseByteArrayElements(env, data, buffer, 0);
return result;
}
JNIEXPORT jint JNICALL Java_com_lanternsoftware_pigpio_PIGPIO_spiWrite
(JNIEnv *env, jclass class, jint handle, jbyteArray data, jint offset, jint count)
{
jbyte *buffer = (*env)->GetByteArrayElements(env, data, 0);
jsize max_length = (*env)->GetArrayLength(env, data) - offset;
int length = (count > max_length) ? max_length : count;
jbyte *offsetBuffer = buffer + offset;
jint result = spiWrite((unsigned)handle, (char *)offsetBuffer, (unsigned)length);
(*env)->ReleaseByteArrayElements(env, data, buffer, JNI_ABORT);
return result;
}
JNIEXPORT jint JNICALL Java_com_lanternsoftware_pigpio_PIGPIO_spiXfer
(JNIEnv *env, jclass class, jint handle, jbyteArray writeData, jint writeOffset, jbyteArray readData, jint readOffset, jint count)
{
jbyte *writeBuffer = (*env)->GetByteArrayElements(env, writeData, 0);
jbyte *readBuffer = (*env)->GetByteArrayElements(env, readData, 0);
jsize max_length = (*env)->GetArrayLength(env, writeData) - writeOffset;
int length = (count > max_length) ? max_length : count;
jbyte *offsetWriteBuffer = writeBuffer + writeOffset;
jbyte *offsetReadBuffer = readBuffer + readOffset;
jint result = spiXfer((unsigned)handle, (char *)offsetWriteBuffer, (char *)offsetReadBuffer, (unsigned)length);
(*env)->ReleaseByteArrayElements(env, writeData, writeBuffer, JNI_ABORT);
(*env)->ReleaseByteArrayElements(env, readData, readBuffer, 0);
return result;
}

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