mirror of
https://github.com/zyphlar/LanternPowerMonitor.git
synced 2024-03-08 14:07:47 +00:00
Compare commits
21 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
95a554422d | ||
![]() |
bf648f069c | ||
![]() |
07765061bd | ||
![]() |
a8236cebc1 | ||
![]() |
b14e6a086d | ||
![]() |
bdf8652450 | ||
![]() |
e0d4dafd3a | ||
![]() |
1369529e8d | ||
![]() |
a23ea4d8b1 | ||
![]() |
b0ffd93f8d | ||
![]() |
b8acfd4ea4 | ||
![]() |
0f730aac32 | ||
![]() |
e37a4905db | ||
![]() |
d7edf3db4a | ||
![]() |
c8319d6369 | ||
![]() |
079206fcd7 | ||
![]() |
d30fc4b4ce | ||
![]() |
8387216c44 | ||
![]() |
119173f2d2 | ||
![]() |
c916b25427 | ||
![]() |
dabefd1e7c |
30
README.md
30
README.md
@ -13,6 +13,10 @@ 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/)
|
||||||
@ -45,15 +49,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.0.7.zip](https://cf.lanternpowermonitor.com/hub_1.0.7.zip)
|
[hub_1.1.1.zip](https://cf.lanternpowermonitor.com/hub_1.1.1.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 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.
|
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.
|
||||||
|
|
||||||
## 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 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. 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. 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.
|
||||||
|
|
||||||
@ -72,27 +76,17 @@ 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 wiring-pi:
|
After that, you need to install pigpio:
|
||||||
```
|
```
|
||||||
sudo apt-get install wiringpi
|
sudo apt-get install pigpio
|
||||||
```
|
```
|
||||||
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.target
|
After=syslog.target network-online.target
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
@ -119,7 +113,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-service-currentmonitor/src/test/java/com/lanternsoftware/currentmonitor/CreateMongoConfig.java that can do this for you.<br>
|
There is a file at lantern-config-currentmonitor/src/main/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.
|
||||||
|
BIN
bom/BOM.xlsx
BIN
bom/BOM.xlsx
Binary file not shown.
10
bom/LCSC_BOM.csv
Normal file
10
bom/LCSC_BOM.csv
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
LCSC Part Number,Quantity
|
||||||
|
C2977589,1
|
||||||
|
C43846,1
|
||||||
|
C43840,1
|
||||||
|
C385441,2
|
||||||
|
C385449,1
|
||||||
|
C385460,1
|
||||||
|
C385498,1
|
||||||
|
C433508,1
|
||||||
|
C397337,16
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
case/3B+/LPM_Case_Flange_3B+.blend
Normal file
BIN
case/3B+/LPM_Case_Flange_3B+.blend
Normal file
Binary file not shown.
BIN
case/3B+/LPM_Case_Flange_3B+.stl
Normal file
BIN
case/3B+/LPM_Case_Flange_3B+.stl
Normal file
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.
105
currentmonitor/lantern-config-currentmonitor/pom.xml
Normal file
105
currentmonitor/lantern-config-currentmonitor/pom.xml
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<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>
|
@ -0,0 +1,14 @@
|
|||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
@ -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.0.7</version>
|
<version>1.1.3</version>
|
||||||
<name>lantern-currentmonitor</name>
|
<name>lantern-currentmonitor</name>
|
||||||
|
|
||||||
<properties>
|
<parent>
|
||||||
<maven.compiler.source>1.8</maven.compiler.source>
|
<groupId>com.lanternsoftware.currentmonitor</groupId>
|
||||||
<maven.compiler.target>1.8</maven.compiler.target>
|
<artifactId>currentmonitor</artifactId>
|
||||||
</properties>
|
<version>1.1.0</version>
|
||||||
|
</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.pi4j</groupId>
|
<groupId>com.lanternsoftware.pigpio</groupId>
|
||||||
<artifactId>pi4j-gpio-extension</artifactId>
|
<artifactId>lantern-pigpio</artifactId>
|
||||||
<version>1.3</version>
|
<version>${pigpio.version}</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>1.0.0</version>
|
<version>${cm.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>1.0.0</version>
|
<version>${util.version}</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.2</version>
|
<version>3.10.1</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>1.8</source>
|
<source>${maven.compiler.source}</source>
|
||||||
<target>1.8</target>
|
<target>${maven.compiler.target}</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.2.1</version>
|
<version>3.3.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||||
<filters>
|
<filters>
|
||||||
|
@ -7,27 +7,38 @@ 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) {
|
||||||
BleHelper.getAdapter().setPowered(true);
|
BleApplication a = null;
|
||||||
BleHelper.requestBusName("com.lanternsoftware");
|
try {
|
||||||
BleHelper.setBasePath("/com/lanternsoftware");
|
BleHelper.getAdapter().setPowered(true);
|
||||||
HubConfigService service = new HubConfigService();
|
BleHelper.requestBusName("com.lanternsoftware");
|
||||||
List<BleCharacteristic> chars = CollectionUtils.transform(service.getCharacteristics(), _c->new BleCharacteristic("HubConfig", _c.getUUID(), _c.name(), _c.getFlags()));
|
BleHelper.setBasePath("/com/lanternsoftware");
|
||||||
chars.forEach(_c->_c.setListener(_listener));
|
List<BleCharacteristic> chars = CollectionUtils.transform(HubConfigService.getCharacteristics(), _c -> new BleCharacteristic("HubConfig", _c.getUUID(), _c.name(), _c.getFlags()));
|
||||||
app = new BleApplication("Lantern", _hubName, new BleService("HubConfig", service.getServiceUUID(), chars));
|
chars.forEach(_c -> _c.setListener(_listener));
|
||||||
|
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() {
|
||||||
app.start();
|
if (app != null)
|
||||||
|
app.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stop() {
|
public void stop() {
|
||||||
app.stop();
|
if (app != null)
|
||||||
|
app.stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,20 @@
|
|||||||
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.pi4j.io.gpio.GpioPinAnalogInput;
|
import com.lanternsoftware.datamodel.currentmonitor.hub.PowerSample;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class BreakerSamples {
|
public class BreakerSamples {
|
||||||
private final Breaker breaker;
|
private final Breaker breaker;
|
||||||
private final GpioPinAnalogInput voltagePin;
|
private final MCP3008Pin voltagePin;
|
||||||
private final GpioPinAnalogInput currentPin;
|
private final MCP3008Pin currentPin;
|
||||||
private final List<PowerSample> samples;
|
private final List<PowerSample> samples;
|
||||||
|
private int cycleCnt;
|
||||||
private int sampleCnt;
|
private int sampleCnt;
|
||||||
|
|
||||||
public BreakerSamples(Breaker _breaker, GpioPinAnalogInput _voltagePin, GpioPinAnalogInput _currentPin, List<PowerSample> _samples) {
|
public BreakerSamples(Breaker _breaker, MCP3008Pin _voltagePin, MCP3008Pin _currentPin, List<PowerSample> _samples) {
|
||||||
breaker = _breaker;
|
breaker = _breaker;
|
||||||
voltagePin = _voltagePin;
|
voltagePin = _voltagePin;
|
||||||
currentPin = _currentPin;
|
currentPin = _currentPin;
|
||||||
@ -23,11 +25,11 @@ public class BreakerSamples {
|
|||||||
return breaker;
|
return breaker;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GpioPinAnalogInput getVoltagePin() {
|
public MCP3008Pin getVoltagePin() {
|
||||||
return voltagePin;
|
return voltagePin;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GpioPinAnalogInput getCurrentPin() {
|
public MCP3008Pin getCurrentPin() {
|
||||||
return currentPin;
|
return currentPin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,8 +37,20 @@ public class BreakerSamples {
|
|||||||
return samples;
|
return samples;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PowerSample getSample(int _sample) {
|
public void incrementCycleCnt() {
|
||||||
return samples.get(_sample);
|
cycleCnt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
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() {
|
||||||
|
@ -1,51 +1,55 @@
|
|||||||
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, AdcGpioProvider> chips = new HashMap<>();
|
private final Map<Integer, MCP3008> 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 void start() {
|
public boolean isDebug() {
|
||||||
try {
|
return debug;
|
||||||
gpio = GpioFactory.getInstance();
|
}
|
||||||
LOG.info("Current Monitor Started");
|
|
||||||
}
|
public void setDebug(boolean _debug) {
|
||||||
catch (Throwable t) {
|
debug = _debug;
|
||||||
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() {
|
||||||
@ -53,21 +57,15 @@ 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) {
|
||||||
GpioPinAnalogInput voltagePin = getPin(0, 0);
|
LOG.info("Calibrating Voltage");
|
||||||
if (voltagePin == null)
|
MCP3008Pin voltagePin = new MCP3008Pin(getChip(0), 0);
|
||||||
return null;
|
int maxSamples = 240000;
|
||||||
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++) {
|
||||||
@ -77,7 +75,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.getValue();
|
samples[offset].voltage = voltagePin.read();
|
||||||
offset++;
|
offset++;
|
||||||
if (samples[offset-1].time > intervalEnd)
|
if (samples[offset-1].time > intervalEnd)
|
||||||
break;
|
break;
|
||||||
@ -128,10 +126,12 @@ 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, 2);
|
sampler = new Sampler(_hub, validBreakers, _intervalMs, 5);
|
||||||
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,34 +140,15 @@ public class CurrentMonitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private GpioPinAnalogInput getPin(int _chip, int _pin) {
|
private synchronized MCP3008 getChip(int _chip) {
|
||||||
GpioPinAnalogInput pin;
|
MCP3008 chip = chips.get(_chip);
|
||||||
synchronized (pins) {
|
if (chip == null) {
|
||||||
AdcGpioProvider chip = chips.get(_chip);
|
String id = "SPI" + _chip;
|
||||||
if (chip == null) {
|
LOG.info("Creating chip {}", id);
|
||||||
SpiChannel channel = SpiChannel.getByNumber(_chip);
|
chip = new MCP3008(PiGpioFactory.getSpiChannel(_chip, 810000, false));
|
||||||
if (channel == null)
|
chips.put(_chip, chip);
|
||||||
return null;
|
|
||||||
try {
|
|
||||||
chip = new MCP3008GpioProvider(channel, 1250000, SpiDevice.DEFAULT_SPI_MODE, false);
|
|
||||||
chips.put(_chip, chip);
|
|
||||||
} catch (IOException _e) {
|
|
||||||
LOG.error("Failed to connect to chip {}", _chip, _e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int pinKey = pinKey(_chip, _pin);
|
|
||||||
pin = pins.get(pinKey);
|
|
||||||
if (pin == null) {
|
|
||||||
pin = gpio.provisionAnalogInputPin(chip, MCP3008Pin.ALL[_pin], String.valueOf(pinKey));
|
|
||||||
pins.put(pinKey, pin);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return pin;
|
return chip;
|
||||||
}
|
|
||||||
|
|
||||||
private Integer pinKey(int _chip, int _pin) {
|
|
||||||
return (_chip*8)+_pin;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void submit(Runnable _runnable) {
|
public void submit(Runnable _runnable) {
|
||||||
@ -185,19 +166,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 int intervalNs;
|
private final long intervalNs;
|
||||||
private final int concurrentBreakerCnt;
|
private final int concurrentBreakerCnt;
|
||||||
|
|
||||||
public Sampler(BreakerHub _hub, List<Breaker> _breakers, int _intervalMs, int _concurrentBreakerCnt) {
|
public Sampler(BreakerHub _hub, List<Breaker> _breakers, long _intervalMs, int _concurrentBreakerCnt) {
|
||||||
hub = _hub;
|
hub = _hub;
|
||||||
GpioPinAnalogInput voltagePin = getPin(0, 0);
|
MCP3008Pin voltagePin = new MCP3008Pin(getChip(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());
|
||||||
GpioPinAnalogInput currentPin = getPin(_b.getChip(), _b.getPin());
|
MCP3008Pin currentPin = new MCP3008Pin(getChip(_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<30000/_breakers.size(); j++) {
|
for (int j=0; j<60000/_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));
|
||||||
@ -213,6 +194,11 @@ 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) {
|
||||||
@ -223,36 +209,83 @@ public class CurrentMonitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
final Date readTime = new Date();
|
final Date readTime = new Date();
|
||||||
final long intervalStart = (interval * intervalNs) + start;
|
intervalStart = (interval * intervalNs) + start;
|
||||||
long intervalEnd = intervalStart + intervalNs;
|
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++;
|
||||||
long cycleEnd = intervalStart + (cycle * (intervalNs / hub.getFrequency()));
|
cycleEnd = intervalStart + (cycle * (intervalNs / hub.getFrequency()));
|
||||||
while (System.nanoTime() < cycleEnd) {
|
curTime = System.nanoTime();
|
||||||
|
while (curTime < cycleEnd) {
|
||||||
for (curBreaker = 0; curBreaker < concurrentBreakerCnt; curBreaker++) {
|
for (curBreaker = 0; curBreaker < concurrentBreakerCnt; curBreaker++) {
|
||||||
PowerSample sample = cycleBreakers[curBreaker].getSample(cycleBreakers[curBreaker].getSampleCnt());
|
PowerSample sample = cycleBreakers[curBreaker].incrementSample();
|
||||||
sample.voltage = cycleBreakers[curBreaker].getVoltagePin().getValue();
|
sample.nanoTime = curTime;
|
||||||
sample.current = cycleBreakers[curBreaker].getCurrentPin().getValue();
|
sample.cycle = cycle;
|
||||||
cycleBreakers[curBreaker].setSampleCnt(cycleBreakers[curBreaker].getSampleCnt()+1);
|
sample.voltage = cycleBreakers[curBreaker].getVoltagePin().read();
|
||||||
|
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) {
|
||||||
double vOffset = 0.0;
|
|
||||||
double iOffset = 0.0;
|
|
||||||
BreakerSamples samples = breaker.get(batch);
|
BreakerSamples samples = breaker.get(batch);
|
||||||
List<PowerSample> validSamples = samples.getSamples().subList(0, samples.getSampleCnt());
|
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 iOffset = 0.0;
|
||||||
for (PowerSample sample : validSamples) {
|
for (PowerSample sample : validSamples) {
|
||||||
vOffset += sample.voltage;
|
vOffset += sample.voltage;
|
||||||
iOffset += sample.current;
|
iOffset += sample.current;
|
||||||
@ -263,6 +296,7 @@ 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)
|
||||||
@ -273,21 +307,26 @@ 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) / samples.getSampleCnt();
|
int lowSampleRatio = (lowSamples * 100) / validSamples.size();
|
||||||
double realPower = Math.abs((hub.getVoltageCalibrationFactor() * hub.getPortCalibrationFactor() * samples.getBreaker().getFinalCalibrationFactor() * pSum) / samples.getSampleCnt());
|
double realPower = (hub.getVoltageCalibrationFactor() * hub.getPortCalibrationFactor() * samples.getBreaker().getFinalCalibrationFactor() * pSum) / validSamples.size();
|
||||||
if ((lowSampleRatio > 75) && realPower < 13.0)
|
if ((lowSampleRatio > 75) && Math.abs(realPower) < 13.0)
|
||||||
realPower = 0.0;
|
realPower = 0.0;
|
||||||
if (samples.getBreaker().getPolarity() == BreakerPolarity.SOLAR)
|
if (samples.getBreaker().getPolarity() == BreakerPolarity.NORMAL)
|
||||||
|
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 = samples.getBreaker().getFinalCalibrationFactor() * Math.sqrt(CollectionUtils.mean(CollectionUtils.transform(validSamples, _p -> _p.current * _p.current)));
|
double iRms = hub.getPortCalibrationFactor() * 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;
|
||||||
@ -298,8 +337,12 @@ 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);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ 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;
|
||||||
@ -35,12 +36,9 @@ 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;
|
||||||
@ -68,16 +66,24 @@ 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 = _p -> {
|
private static final PowerListener logger = new PowerListener() {
|
||||||
if (!config.isDebug()) {
|
@Override
|
||||||
_p.setHubVersion(version);
|
public void onPowerEvent(BreakerPower _power) {
|
||||||
if (breakerConfig != null)
|
if (!config.isDebug()) {
|
||||||
_p.setAccountId(breakerConfig.getAccountId());
|
_power.setHubVersion(version);
|
||||||
synchronized (readings) {
|
if (breakerConfig != null)
|
||||||
readings.add(_p);
|
_power.setAccountId(breakerConfig.getAccountId());
|
||||||
}
|
synchronized (readings) {
|
||||||
} else
|
readings.add(_power);
|
||||||
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
|
||||||
@ -210,17 +216,15 @@ 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) {
|
||||||
LOG.error("Failed to load config file from {}", WORKING_DIR + "config.json");
|
config = new MonitorConfig();
|
||||||
return;
|
ResourceLoader.writeFile(WORKING_DIR + "config.json", DaoSerializer.toJson(config));
|
||||||
}
|
}
|
||||||
pool = new HttpPool(10, 10, config.getSocketTimeout(), config.getConnectTimeout(), config.getSocketTimeout());
|
pool = HttpPool.builder().withValidateSSLCertificates(!config.isAcceptSelfSignedCertificates()).build();
|
||||||
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.start();
|
monitor.setPostSamples(config.isPostSamples());
|
||||||
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())) {
|
||||||
@ -231,7 +235,8 @@ 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)) {
|
||||||
while (true) {
|
int configAttempts = 0;
|
||||||
|
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);
|
||||||
@ -239,8 +244,11 @@ 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();
|
||||||
@ -266,13 +274,18 @@ 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()) {
|
||||||
CalibrationResult cal = monitor.calibrateVoltage(hub.getVoltageCalibrationFactor());
|
try {
|
||||||
if (cal != null) {
|
CalibrationResult cal = monitor.calibrateVoltage(hub.getVoltageCalibrationFactor());
|
||||||
hub.setVoltageCalibrationFactor(cal.getVoltageCalibrationFactor());
|
if (cal != null) {
|
||||||
hub.setFrequency(cal.getFrequency());
|
hub.setVoltageCalibrationFactor(cal.getVoltageCalibrationFactor());
|
||||||
config.setNeedsCalibration(false);
|
hub.setFrequency(cal.getFrequency());
|
||||||
ResourceLoader.writeFile(WORKING_DIR + "config.json", DaoSerializer.toJson(config));
|
config.setNeedsCalibration(false);
|
||||||
post(DaoSerializer.toZipBson(breakerConfig), "config");
|
ResourceLoader.writeFile(WORKING_DIR + "config.json", DaoSerializer.toJson(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());
|
||||||
@ -288,17 +301,11 @@ public class MonitorApp {
|
|||||||
monitor.stop();
|
monitor.stop();
|
||||||
pool.shutdown();
|
pool.shutdown();
|
||||||
}, "Monitor Shutdown"));
|
}, "Monitor Shutdown"));
|
||||||
Console c = System.console();
|
synchronized (monitor) {
|
||||||
BufferedReader reader = (c == null)?new BufferedReader(new InputStreamReader(System.in)):null;
|
|
||||||
while (running.get()) {
|
|
||||||
try {
|
try {
|
||||||
String command = c != null ? c.readLine() : reader.readLine();
|
monitor.wait();
|
||||||
if (NullUtils.isEqual("exit", command))
|
} catch (InterruptedException _e) {
|
||||||
break;
|
LOG.error("Interrupted, shutting down", _e);
|
||||||
}
|
|
||||||
catch (Exception _e) {
|
|
||||||
LOG.error("Exception while reading from console input", _e);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -360,7 +367,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().toString() + ".min", payload);
|
ResourceLoader.writeFile(WORKING_DIR + "cache/" + UUID.randomUUID() + ".min", payload);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (post != null) {
|
if (post != null) {
|
||||||
|
@ -2,6 +2,7 @@ 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;
|
||||||
@ -12,11 +13,13 @@ public class MonitorConfig {
|
|||||||
private String authCode;
|
private String authCode;
|
||||||
private String username;
|
private String username;
|
||||||
private String password;
|
private String password;
|
||||||
private int hub;
|
private int hub = -1;
|
||||||
private boolean debug;
|
private boolean debug;
|
||||||
private int connectTimeout;
|
private int connectTimeout;
|
||||||
private int socketTimeout;
|
private int socketTimeout;
|
||||||
private boolean needsCalibration;
|
private boolean postSamples = false;
|
||||||
|
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;
|
||||||
@ -34,7 +37,7 @@ public class MonitorConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getHost() {
|
public String getHost() {
|
||||||
return host;
|
return NullUtils.isEmpty(host) ? "https://lanternpowermonitor.com/currentmonitor/" : host;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHost(String _host) {
|
public void setHost(String _host) {
|
||||||
@ -97,6 +100,14 @@ 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;
|
||||||
}
|
}
|
||||||
@ -105,6 +116,14 @@ 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;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
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);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
package com.lanternsoftware.currentmonitor;
|
|
||||||
|
|
||||||
public class PowerSample {
|
|
||||||
public double voltage;
|
|
||||||
public double current;
|
|
||||||
}
|
|
@ -0,0 +1,29 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
@ -34,7 +34,9 @@ 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());
|
||||||
@ -57,7 +59,9 @@ 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"));
|
||||||
|
@ -2,12 +2,6 @@
|
|||||||
<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">
|
||||||
@ -21,6 +15,7 @@
|
|||||||
</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"/>
|
||||||
|
@ -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.0.0</version>
|
<version>1.1.0</version>
|
||||||
<name>lantern-dataaccess-currentmonitor</name>
|
<name>lantern-dataaccess-currentmonitor</name>
|
||||||
|
|
||||||
<properties>
|
<parent>
|
||||||
<maven.compiler.source>1.8</maven.compiler.source>
|
<groupId>com.lanternsoftware.currentmonitor</groupId>
|
||||||
<maven.compiler.target>1.8</maven.compiler.target>
|
<artifactId>currentmonitor</artifactId>
|
||||||
</properties>
|
<version>1.1.0</version>
|
||||||
|
</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>1.0.0</version>
|
<version>${cm.version}</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>1.0.0</version>
|
<version>${rules.version}</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>1.0.0</version>
|
<version>${util.version}</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.2</version>
|
<version>3.10.1</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>1.8</source>
|
<source>${maven.compiler.source}</source>
|
||||||
<target>1.8</target>
|
<target>${maven.compiler.target}</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>2.4</version>
|
<version>3.2.1</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<phase>package</phase>
|
<phase>package</phase>
|
||||||
@ -73,16 +73,6 @@
|
|||||||
</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>
|
||||||
|
@ -4,22 +4,31 @@ 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 dao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.CONFIG_PATH + "mongo.cfg"));
|
CurrentMonitorDao sourceDao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.CONFIG_PATH + "mongo.cfg"));
|
||||||
CurrentMonitorDao backupDao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.BACKUP_DEST_PATH + "mongo.cfg"));
|
CurrentMonitorDao destDao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.BACKUP_DEST_PATH + "mongo.cfg"));
|
||||||
Date now = new Date();
|
ExecutorService ex = Executors.newFixedThreadPool(8);
|
||||||
for (Account a : dao.getProxy().queryAll(Account.class)) {
|
List<Future<?>> tasks = new ArrayList<>();
|
||||||
|
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());
|
||||||
@ -27,28 +36,35 @@ public class BackupMinutes {
|
|||||||
a.setTimezone("America/Chicago");
|
a.setTimezone("America/Chicago");
|
||||||
}
|
}
|
||||||
TimeZone tz = TimeZone.getTimeZone(a.getTimezone());
|
TimeZone tz = TimeZone.getTimeZone(a.getTimezone());
|
||||||
HubPowerMinute minute = dao.getProxy().queryOne(HubPowerMinute.class, new DaoQuery("account_id", a.getId()), DaoSort.sort("minute"));
|
HubPowerMinute firstMinute = sourceDao.getProxy().queryOne(HubPowerMinute.class, new DaoQuery("account_id", a.getId()), DaoSort.sort("minute"));
|
||||||
if (minute == null)
|
if (firstMinute == null)
|
||||||
continue;
|
continue;
|
||||||
HubPowerMinute lastBackup = backupDao.getProxy().queryOne(HubPowerMinute.class, new DaoQuery("account_id", a.getId()), DaoSort.sortDesc("minute"));
|
HubPowerMinute lastMinute = sourceDao.getProxy().queryOne(HubPowerMinute.class, new DaoQuery("account_id", a.getId()), DaoSort.sortDesc("minute"));
|
||||||
Date start = lastBackup == null ? DateUtils.getMidnightBefore(minute.getMinuteAsDate(), tz) : lastBackup.getMinuteAsDate();
|
HubPowerMinute lastBackup = destDao.getProxy().queryOne(HubPowerMinute.class, new DaoQuery("account_id", a.getId()), DaoSort.sortDesc("minute"));
|
||||||
// Date start = DateUtils.date(10,16,2021,tz);
|
Date start = lastBackup == null ? DateUtils.getMidnightBefore(firstMinute.getMinuteAsDate(), tz) : lastBackup.getMinuteAsDate();
|
||||||
|
Date lastMin = lastMinute.getMinuteAsDate();
|
||||||
Date end = DateUtils.addDays(start, 1, tz);
|
Date end = DateUtils.addDays(start, 1, tz);
|
||||||
while (start.before(now)) {
|
while (start.before(lastMin)) {
|
||||||
DebugTimer t2 = new DebugTimer("Account Id: " + a.getId() + " Query Day " + DateUtils.format("MM/dd/yyyy", tz, start));
|
final Date curStart = start;
|
||||||
List<HubPowerMinute> minutes = dao.getProxy().query(HubPowerMinute.class, new DaoQuery("account_id", a.getId()).andBetweenInclusiveExclusive("minute", (int) (start.getTime() / 60000), (int) (end.getTime() / 60000)));
|
final Date curEnd = end;
|
||||||
t2.stop();
|
tasks.add(ex.submit(() -> {
|
||||||
if (!minutes.isEmpty()) {
|
DebugTimer t2 = new DebugTimer("Account Id: " + a.getId() + " Query Day " + DateUtils.format("MM/dd/yyyy", tz, curStart));
|
||||||
DebugTimer t3 = new DebugTimer("Save Day");
|
List<HubPowerMinute> minutes = sourceDao.getProxy().query(HubPowerMinute.class, new DaoQuery("account_id", a.getId()).andBetweenInclusiveExclusive("minute", (int) (curStart.getTime() / 60000), (int) (curEnd.getTime() / 60000)));
|
||||||
backupDao.getProxy().save(minutes);
|
t2.stop();
|
||||||
t3.stop();
|
if (!minutes.isEmpty()) {
|
||||||
}
|
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();
|
||||||
}
|
}
|
||||||
dao.shutdown();
|
ConcurrencyUtils.getAll(tasks);
|
||||||
backupDao.shutdown();
|
ex.shutdown();
|
||||||
|
sourceDao.shutdown();
|
||||||
|
destDao.shutdown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ 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;
|
||||||
@ -44,7 +45,6 @@ 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,6 +54,7 @@ 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);
|
||||||
@ -65,5 +66,8 @@ 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();
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ 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;
|
||||||
@ -90,6 +91,9 @@ 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() {
|
||||||
@ -303,7 +307,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.before(end)) {
|
while ((month != null) && 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);
|
||||||
}
|
}
|
||||||
@ -326,6 +330,8 @@ 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);
|
||||||
@ -412,13 +418,13 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
|
|||||||
putEnergySummary(summary);
|
putEnergySummary(summary);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateChargeSummary(BreakerConfig _config, EnergySummary _energySummary, TimeZone _tz) {
|
public 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.before(lookback))
|
if ((lookback == null) || ((cycleStart != null) && cycleStart.before(lookback)))
|
||||||
lookback = cycleStart;
|
lookback = cycleStart;
|
||||||
}
|
}
|
||||||
if (lookback != null) {
|
if (lookback != null) {
|
||||||
@ -462,7 +468,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.before(loopEnd)) {
|
while ((yearMonthStart != null) && 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));
|
||||||
@ -482,17 +488,13 @@ 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;
|
||||||
rebuildSummaries(_accountId, firstMinute.getMinuteAsDate(), new Date());
|
HubPowerMinute lastMinute = proxy.queryOne(HubPowerMinute.class, new DaoQuery("account_id", _accountId), DaoSort.sortDesc("minute"));
|
||||||
|
rebuildSummaries(_accountId, firstMinute.getMinuteAsDate(), lastMinute.getMinuteAsDate());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -660,7 +662,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, acct.getPassword()))
|
if ((acct == null) || !BCrypt.checkpw(_password, NullUtils.makeNotNull(acct.getPassword())))
|
||||||
return null;
|
return null;
|
||||||
return toAuthCode(acct.getId(), acct.getAuxiliaryAccountIds());
|
return toAuthCode(acct.getId(), acct.getAuxiliaryAccountIds());
|
||||||
}
|
}
|
||||||
@ -691,6 +693,11 @@ 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;
|
||||||
@ -777,6 +784,8 @@ 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));
|
||||||
@ -800,6 +809,16 @@ 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;
|
||||||
|
@ -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.0.0</version>
|
<version>1.1.0</version>
|
||||||
<name>lantern-datamodel-currentmonitor</name>
|
<name>lantern-datamodel-currentmonitor</name>
|
||||||
|
|
||||||
<properties>
|
<parent>
|
||||||
<maven.compiler.source>1.8</maven.compiler.source>
|
<groupId>com.lanternsoftware.currentmonitor</groupId>
|
||||||
<maven.compiler.target>1.8</maven.compiler.target>
|
<artifactId>currentmonitor</artifactId>
|
||||||
</properties>
|
<version>1.1.0</version>
|
||||||
|
</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>1.0.0</version>
|
<version>${util.version}</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.2</version>
|
<version>3.10.1</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>1.8</source>
|
<source>${maven.compiler.source}</source>
|
||||||
<target>1.8</target>
|
<target>${maven.compiler.target}</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>2.4</version>
|
<version>3.2.1</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<phase>package</phase>
|
<phase>package</phase>
|
||||||
@ -58,16 +58,6 @@
|
|||||||
</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>
|
||||||
|
@ -21,11 +21,13 @@ 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() {
|
||||||
@ -139,6 +141,14 @@ 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;
|
||||||
}
|
}
|
||||||
@ -148,7 +158,7 @@ public class Breaker implements IIdentical<Breaker> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public BreakerPolarity getPolarity() {
|
public BreakerPolarity getPolarity() {
|
||||||
return polarity;
|
return polarity == null ? BreakerPolarity.NORMAL : polarity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPolarity(BreakerPolarity _polarity) {
|
public void setPolarity(BreakerPolarity _polarity) {
|
||||||
@ -184,6 +194,14 @@ 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;
|
||||||
}
|
}
|
||||||
@ -269,7 +287,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 && 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);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -10,6 +10,7 @@ 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> {
|
||||||
@ -202,8 +203,20 @@ 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(billingRates, BillingRate::getCurrency));
|
return CollectionUtils.getFirst(CollectionUtils.transformToSet(CollectionUtils.aggregate(billingPlans, BillingPlan::getRates), BillingRate::getCurrency));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMainsPowerTrackedForMeter(int _meter) {
|
||||||
|
return CollectionUtils.anyQualify(getAllBreakers(), _b->_b.isMain() && (_b.getMeter() == _meter));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -182,6 +182,20 @@ 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));
|
||||||
|
@ -11,6 +11,8 @@ 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;
|
||||||
|
|
||||||
@ -39,15 +41,31 @@ public class BreakerHub implements IIdentical<BreakerHub> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public double getPortCalibrationFactor() {
|
public double getPortCalibrationFactor() {
|
||||||
return portCalibrationFactor == 0.0?1.25:portCalibrationFactor;
|
return portCalibrationFactor == 0.0?1.20: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;
|
return frequency == 0 ? 60 : frequency;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFrequency(int _frequency) {
|
public void setFrequency(int _frequency) {
|
||||||
@ -73,7 +91,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 && frequency == _o.frequency && Objects.equals(bluetoothMac, _o.bluetoothMac);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -2,5 +2,7 @@ package com.lanternsoftware.datamodel.currentmonitor;
|
|||||||
|
|
||||||
public enum BreakerPolarity {
|
public enum BreakerPolarity {
|
||||||
NORMAL,
|
NORMAL,
|
||||||
SOLAR;
|
SOLAR,
|
||||||
|
BI_DIRECTIONAL,
|
||||||
|
BI_DIRECTIONAL_INVERTED
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
package com.lanternsoftware.datamodel.currentmonitor;
|
||||||
|
|
||||||
|
public enum EmailProvider {
|
||||||
|
SENDGRID,
|
||||||
|
MAILJET
|
||||||
|
}
|
@ -8,7 +8,6 @@ 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;
|
||||||
@ -26,6 +25,7 @@ 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,6 +40,7 @@ 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();
|
||||||
@ -50,29 +51,30 @@ public class EnergySummary {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void addEnergy(BreakerGroup _group, List<HubPowerMinute> _hubPower) {
|
public void addEnergy(BreakerGroup _group, List<HubPowerMinute> _hubPower) {
|
||||||
Map<String, Breaker> breakers = CollectionUtils.transformToMap(_group.getAllBreakers(), Breaker::getKey);
|
Map<Integer, Breaker> breakers = CollectionUtils.transformToMap(_group.getAllBreakers(), Breaker::getIntKey);
|
||||||
Map<String, BreakerGroup> breakerKeyToGroup = new HashMap<>();
|
Map<Integer, 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.getKey(), group);
|
breakerKeyToGroup.put(b.getIntKey(), group);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addEnergy(breakers, breakerKeyToGroup, _hubPower);
|
addEnergy(breakers, breakerKeyToGroup, _hubPower);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addEnergy(Map<String, Breaker> _breakers, Map<String, BreakerGroup> _breakerKeyToGroup, List<HubPowerMinute> _hubPower) {
|
public void addEnergy(Map<Integer, Breaker> _breakers, Map<Integer, 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())) {
|
||||||
String key = breaker.breakerKey();
|
int key = breaker.breakerIntKey();
|
||||||
Breaker b = _breakers.get(key);
|
Breaker b = _breakers.get(key);
|
||||||
if (b == null)
|
if (b == null)
|
||||||
continue;
|
continue;
|
||||||
@ -84,10 +86,12 @@ 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 (power > 0)
|
if (!meterMainsTracked.contains(b.getMeter()) || b.isMain()) {
|
||||||
meter.usage[idx] += power;
|
if (power > 0)
|
||||||
else
|
meter.usage[idx] += power;
|
||||||
meter.solar[idx] -= power;
|
else
|
||||||
|
meter.solar[idx] -= power;
|
||||||
|
}
|
||||||
addEnergy(group.getId(), minute, power);
|
addEnergy(group.getId(), minute, power);
|
||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
@ -125,7 +129,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())) {
|
||||||
String key = breaker.breakerKey();
|
int key = breaker.breakerIntKey();
|
||||||
Breaker b = _breakers.get(key);
|
Breaker b = _breakers.get(key);
|
||||||
if (b == null)
|
if (b == null)
|
||||||
continue;
|
continue;
|
||||||
@ -136,9 +140,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 ((b.getPolarity() == BreakerPolarity.SOLAR) && (meter.flow[idx] < 0.0))
|
if (power < 0 && (meter.flow[idx] < 0.0))
|
||||||
flow -= meter.flow[idx] * (power / meter.solar[idx]);
|
flow -= meter.flow[idx] * (power / meter.solar[idx]);
|
||||||
else if ((b.getPolarity() != BreakerPolarity.SOLAR) && (meter.flow[idx] > 0.0))
|
else if (power > 0 && (meter.flow[idx] > 0.0))
|
||||||
flow += meter.flow[idx] * (power / meter.usage[idx]);
|
flow += meter.flow[idx] * (power / meter.usage[idx]);
|
||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
@ -148,11 +152,11 @@ public class EnergySummary {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void resetEnergy(Date _readTime) {
|
public void resetEnergy(Date _readTime) {
|
||||||
if (energy == null)
|
if (energy != null) {
|
||||||
return;
|
int idx = viewMode.blockIndex(start, _readTime, timezone);
|
||||||
int idx = viewMode.blockIndex(start, _readTime, timezone);
|
if (idx < energy.length)
|
||||||
if (idx < energy.length)
|
energy[idx] = 0f;
|
||||||
energy[idx] = 0f;
|
}
|
||||||
for (EnergySummary subGroup : CollectionUtils.makeNotNull(subGroups)) {
|
for (EnergySummary subGroup : CollectionUtils.makeNotNull(subGroups)) {
|
||||||
subGroup.resetEnergy(_readTime);
|
subGroup.resetEnergy(_readTime);
|
||||||
}
|
}
|
||||||
@ -288,6 +292,14 @@ 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;
|
||||||
}
|
}
|
||||||
@ -362,7 +374,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) {
|
if (_includeSubgroups && !isMain()) {
|
||||||
for (EnergySummary group : CollectionUtils.makeNotNull(subGroups)) {
|
for (EnergySummary group : CollectionUtils.makeNotNull(subGroups)) {
|
||||||
joules += group.joules(_selectedBreakers, true, _mode);
|
joules += group.joules(_selectedBreakers, true, _mode);
|
||||||
}
|
}
|
||||||
|
@ -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(15, CharacteristicFlag.WRITE);
|
ReloadConfig(16, CharacteristicFlag.WRITE);
|
||||||
|
|
||||||
public final int idx;
|
public final int idx;
|
||||||
public final UUID uuid;
|
public final UUID uuid;
|
||||||
|
@ -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 class HubConfigService {
|
public abstract 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 class HubConfigService {
|
|||||||
return serviceUUID;
|
return serviceUUID;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<HubConfigCharacteristic> getCharacteristics() {
|
public static List<HubConfigCharacteristic> getCharacteristics() {
|
||||||
return Arrays.asList(HubConfigCharacteristic.values());
|
return Arrays.asList(HubConfigCharacteristic.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,6 +36,10 @@ 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);
|
||||||
}
|
}
|
||||||
|
@ -15,59 +15,45 @@ 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, AtomicInteger> ctDuplicates = new TreeMap<>();
|
Map<Integer, Breaker> breakers = CollectionUtils.transformToMap(_config.getAllBreakers(), Breaker::getIntKey);
|
||||||
for (Breaker breaker : CollectionUtils.makeNotNull(_config.getAllBreakers())) {
|
for (Breaker breaker : breakers.values()) {
|
||||||
if (breaker.getSizeAmps() <= 20) {
|
if (bom.isUntrackedBottom(breakers, breaker))
|
||||||
ctCnts.computeIfAbsent(20, (_k) -> new AtomicInteger(0)).getAndIncrement();
|
continue;
|
||||||
if (breaker.getType() == BreakerType.DOUBLE_POLE_TOP_ONE_CT)
|
for (int size : ctSizes.keySet()) {
|
||||||
ctDuplicates.computeIfAbsent(20, (_k) -> new AtomicInteger(0)).getAndIncrement();
|
if (breaker.getSizeAmps() <= size) {
|
||||||
|
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 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://store.lanternpowermonitor.com/product/assembled-lantern-power-monitor-pcb/1", 1.00, 5.00, hubCnt));
|
||||||
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://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("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("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("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("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-0%d", ctCnt.getKey()), "N/A", 5.00, 7.00, ctCnt.getValue().get()));
|
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()));
|
||||||
}
|
}
|
||||||
return bom;
|
return bom;
|
||||||
}
|
}
|
||||||
@ -93,4 +79,11 @@ 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;
|
||||||
|
}
|
||||||
}
|
}
|
@ -28,6 +28,8 @@ 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;
|
||||||
@ -40,6 +42,8 @@ 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;
|
||||||
|
@ -35,11 +35,13 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,11 +57,13 @@ 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
@ -9,7 +9,6 @@ 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;
|
||||||
@ -38,6 +37,7 @@ 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,6 +61,7 @@ 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")));
|
||||||
|
@ -0,0 +1,41 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
@ -15,6 +15,7 @@ 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
|
||||||
@ -25,3 +26,6 @@ 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
|
||||||
|
@ -1,54 +1,41 @@
|
|||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<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">
|
||||||
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.0.0</version>
|
<version>1.1.0</version>
|
||||||
<name>lantern-service-currentmonitor</name>
|
<name>lantern-service-currentmonitor</name>
|
||||||
|
|
||||||
<properties>
|
<parent>
|
||||||
<maven.compiler.source>1.8</maven.compiler.source>
|
<groupId>com.lanternsoftware.currentmonitor</groupId>
|
||||||
<maven.compiler.target>1.8</maven.compiler.target>
|
<artifactId>currentmonitor</artifactId>
|
||||||
</properties>
|
<version>1.1.0</version>
|
||||||
|
</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>1.0.0</version>
|
<version>${cm.version}</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>1.0.0</version>
|
<version>${util.version}</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>1.0.0</version>
|
<version>${util.version}</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>1.0.0</version>
|
<version>${rules.version}</version>
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.google.api-client</groupId>
|
|
||||||
<artifactId>google-api-client</artifactId>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>javax</groupId>
|
<groupId>javax</groupId>
|
||||||
@ -67,9 +54,14 @@
|
|||||||
<version>1.2.3</version>
|
<version>1.2.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.sendgrid</groupId>
|
<groupId>com.auth0</groupId>
|
||||||
<artifactId>sendgrid-java</artifactId>
|
<artifactId>java-jwt</artifactId>
|
||||||
<version>4.7.2</version>
|
<version>3.19.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.mailjet</groupId>
|
||||||
|
<artifactId>mailjet-client</artifactId>
|
||||||
|
<version>4.2.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<build>
|
<build>
|
||||||
@ -82,7 +74,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.2</version>
|
<version>3.10.1</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<goals>
|
<goals>
|
||||||
@ -95,13 +87,13 @@
|
|||||||
<optimize>true</optimize>
|
<optimize>true</optimize>
|
||||||
<showDeprecation>true</showDeprecation>
|
<showDeprecation>true</showDeprecation>
|
||||||
<encoding>UTF-8</encoding>
|
<encoding>UTF-8</encoding>
|
||||||
<source>1.8</source>
|
<source>${maven.compiler.source}</source>
|
||||||
<target>1.8</target>
|
<target>${maven.compiler.target}</target>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<artifactId>maven-war-plugin</artifactId>
|
<artifactId>maven-war-plugin</artifactId>
|
||||||
<version>2.5</version>
|
<version>3.3.2</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<webResources>
|
<webResources>
|
||||||
<resource>
|
<resource>
|
||||||
|
@ -6,8 +6,9 @@ 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.external.LanternFiles;
|
|
||||||
import com.lanternsoftware.util.dao.mongo.MongoConfig;
|
import com.lanternsoftware.util.dao.mongo.MongoConfig;
|
||||||
|
import com.lanternsoftware.util.external.LanternFiles;
|
||||||
|
import com.lanternsoftware.util.http.HttpFactory;
|
||||||
|
|
||||||
import javax.servlet.ServletContextEvent;
|
import javax.servlet.ServletContextEvent;
|
||||||
import javax.servlet.ServletContextListener;
|
import javax.servlet.ServletContextListener;
|
||||||
@ -17,9 +18,12 @@ 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
|
||||||
@ -27,11 +31,14 @@ 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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
package com.lanternsoftware.currentmonitor.email;
|
||||||
|
|
||||||
|
import com.lanternsoftware.datamodel.currentmonitor.EmailCredentials;
|
||||||
|
|
||||||
|
public interface IEmailProvider {
|
||||||
|
int sendTextEmail(EmailCredentials _credentials, String _to, String _subject, String _message);
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
@ -1,14 +1,15 @@
|
|||||||
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;
|
||||||
@ -16,19 +17,27 @@ import javax.servlet.http.HttpServletResponse;
|
|||||||
|
|
||||||
@WebServlet("/auth/*")
|
@WebServlet("/auth/*")
|
||||||
public class AuthServlet extends LanternServlet {
|
public class AuthServlet extends LanternServlet {
|
||||||
private static final Logger logger = LoggerFactory.getLogger(AuthServlet.class);
|
private static final GoogleSSO googleSSO = new GoogleSSO(LanternFiles.CONFIG_PATH + "google_sso.txt");
|
||||||
|
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");
|
||||||
if (NullUtils.isEmpty(authCode)) {
|
String idToken = _req.getHeader("id_token");
|
||||||
|
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"))
|
||||||
logger.info("Attempting google SSO");
|
email = googleSSO.signin(auth.getPassword());
|
||||||
authCode = GoogleAuthHelper.signin(auth.getPassword(), DateUtils.fromTimeZoneId(_req.getHeader("timezone")));
|
else
|
||||||
} 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);
|
||||||
|
@ -4,6 +4,7 @@ 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;
|
||||||
@ -40,6 +41,8 @@ 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);
|
||||||
zipBsonResponse(_rep, Globals.dao.getMergedConfig(_authCode));
|
config = Globals.dao.getMergedConfig(_authCode);
|
||||||
|
RulesEngine.instance().sendFcmMessage(config.getAccountId(), config);
|
||||||
|
zipBsonResponse(_rep, config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,13 +17,14 @@ 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.dao.rebuildSummariesAsync(DaoSerializer.toInteger(CollectionUtils.get(path, 0)));
|
Globals.opsExecutor.submit(() -> Globals.dao.rebuildSummaries(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.dao.rebuildSummariesAsync(id);
|
Globals.opsExecutor.submit(() -> Globals.dao.rebuildSummaries(id));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,19 @@
|
|||||||
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;
|
||||||
@ -25,13 +22,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 String api_key = ResourceLoader.loadFileAsString(LanternFiles.CONFIG_PATH + "sendgrid.txt");
|
protected static final EmailCredentials credentials = DaoSerializer.parse(ResourceLoader.loadFileAsString(LanternFiles.CONFIG_PATH + "email.json"), EmailCredentials.class);
|
||||||
|
protected static final IEmailProvider provider = new MailJetProvider();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Configuration getFreemarkerConfig() {
|
protected Configuration getFreemarkerConfig() {
|
||||||
@ -63,25 +60,11 @@ 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");
|
||||||
if (EmailValidator.getInstance().isValid(email)) {
|
Account account = Globals.dao.getAccountByUsername(email);
|
||||||
|
if ((account != null) && EmailValidator.getInstance().isValid(email)) {
|
||||||
String key = Globals.dao.addPasswordResetKey(email);
|
String key = Globals.dao.addPasswordResetKey(email);
|
||||||
Email from = new Email("info@lanternsoftware.com");
|
int status = provider.sendTextEmail(credentials, email, "Password Reset - Lantern Power Monitor", "Reset your password using this link:\n" + credentials.getServerUrlBase() + "resetPassword/" + key);
|
||||||
String subject = "Password Reset - Lantern Power Monitor";
|
zipBsonResponse(_resp, new DaoEntity("success", status == 200));
|
||||||
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);
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
@ -14,26 +14,27 @@ 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"));
|
jsonResponse(_rep, SignupResponse.error("An account for " + auth.getUsername() + " already exists"), binary);
|
||||||
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"));
|
jsonResponse(_rep, SignupResponse.error(auth.getUsername() + " is not a valid email address"), binary);
|
||||||
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"));
|
jsonResponse(_rep, SignupResponse.error("Your password must be at least 8 characters long"), binary);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (NullUtils.isEqual("password", auth.getPassword())) {
|
if (NullUtils.isEqual("password", auth.getPassword())) {
|
||||||
jsonResponse(_rep, SignupResponse.error("Seriously? \"password\"? Come on."));
|
jsonResponse(_rep, SignupResponse.error("Seriously? \"password\"? Come on."), binary);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
acct = new Account();
|
acct = new Account();
|
||||||
@ -42,6 +43,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()));
|
jsonResponse(_rep, SignupResponse.success(authCode, acct.getTimezone()), binary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
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) {
|
||||||
|
}
|
||||||
|
}
|
@ -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 SecureConsoleServlet {
|
public class ConsoleServlet extends AuthenticatedConsoleServlet {
|
||||||
private static final Logger logger = LoggerFactory.getLogger(ConsoleServlet.class);
|
private static final Logger logger = LoggerFactory.getLogger(ConsoleServlet.class);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -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 SecureConsoleServlet {
|
public class ExportServlet extends AuthenticatedConsoleServlet {
|
||||||
private static final Logger logger = LoggerFactory.getLogger(ExportServlet.class);
|
private static final Logger logger = LoggerFactory.getLogger(ExportServlet.class);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
package com.lanternsoftware.currentmonitor.servlet.console;
|
package com.lanternsoftware.currentmonitor.servlet.console;
|
||||||
|
|
||||||
import com.lanternsoftware.currentmonitor.servlet.FreemarkerCMServlet;
|
import com.lanternsoftware.currentmonitor.context.Globals;
|
||||||
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.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;
|
||||||
@ -10,23 +12,28 @@ import javax.servlet.http.HttpServletRequest;
|
|||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
@WebServlet("/gso")
|
@WebServlet("/gso")
|
||||||
public class GsoServlet extends FreemarkerCMServlet {
|
public class GsoServlet extends SecureConsoleServlet {
|
||||||
|
private static final GoogleSSO googleSSO = new GoogleSSO(LanternFiles.CONFIG_PATH + "google_sso.txt");
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doGet(HttpServletRequest _req, HttpServletResponse _rep) {
|
protected void get(HttpServletRequest _req, HttpServletResponse _rep) {
|
||||||
render(_rep, "login.ftl", model(_req));
|
render(_rep, "login.ftl", model(_req));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doPost(HttpServletRequest _req, HttpServletResponse _rep) {
|
protected void post(HttpServletRequest _req, HttpServletResponse _rep) {
|
||||||
String code = getRequestPayloadAsString(_req);
|
String code = getRequestPayloadAsString(_req);
|
||||||
if (NullUtils.isNotEmpty(code)) {
|
if (NullUtils.isNotEmpty(code)) {
|
||||||
String authCode = GoogleAuthHelper.signin(code, null);
|
String email = googleSSO.signin(code);
|
||||||
if (NullUtils.isNotEmpty(authCode)) {
|
if (NullUtils.isNotEmpty(email)) {
|
||||||
Cookie authCookie = new Cookie("auth_code", authCode);
|
String authCode = Globals.dao.getAuthCodeForEmail(email, DateUtils.fromTimeZoneId(_req.getHeader("timezone")));
|
||||||
authCookie.setMaxAge(157680000);
|
if (NullUtils.isNotEmpty(authCode)) {
|
||||||
authCookie.setSecure(true);
|
Cookie authCookie = new Cookie("auth_code", authCode);
|
||||||
_rep.addCookie(authCookie);
|
authCookie.setMaxAge(157680000);
|
||||||
_req.getSession().setAttribute("auth_code", authCode);
|
authCookie.setSecure(true);
|
||||||
|
_rep.addCookie(authCookie);
|
||||||
|
_req.getSession().setAttribute("auth_code", authCode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,31 +1,22 @@
|
|||||||
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 FreemarkerCMServlet {
|
public class LoginServlet extends SecureConsoleServlet {
|
||||||
@Override
|
@Override
|
||||||
protected void doGet(HttpServletRequest _req, HttpServletResponse _rep) {
|
protected void get(HttpServletRequest _req, HttpServletResponse _rep) {
|
||||||
render(_rep, "login.ftl", model(_req));
|
render(_rep, "login.ftl", model(_req));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doPost(HttpServletRequest _req, HttpServletResponse _rep) {
|
protected void post(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);
|
||||||
|
@ -1,18 +1,14 @@
|
|||||||
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 FreemarkerCMServlet {
|
public class LogoutServlet extends AuthenticatedConsoleServlet {
|
||||||
@Override
|
@Override
|
||||||
protected void doGet(HttpServletRequest _req, HttpServletResponse _rep) {
|
protected void get(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);
|
||||||
@ -22,6 +18,6 @@ public class LogoutServlet extends FreemarkerCMServlet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doPost(HttpServletRequest _req, HttpServletResponse _rep) {
|
protected void post(HttpServletRequest _req, HttpServletResponse _rep) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,48 +1,40 @@
|
|||||||
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) {
|
||||||
AuthCode code = getAuthCode(_req, _rep);
|
if (isSecure(_req, _rep))
|
||||||
if (code != null)
|
get(_req, _rep);
|
||||||
get(code, _req, _rep);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void get(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
|
protected void get(HttpServletRequest _req, HttpServletResponse _rep) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doPost(HttpServletRequest _req, HttpServletResponse _rep) {
|
protected void doPost(HttpServletRequest _req, HttpServletResponse _rep) {
|
||||||
AuthCode code = getAuthCode(_req, _rep);
|
if (isSecure(_req, _rep))
|
||||||
if (code != null)
|
post(_req, _rep);
|
||||||
post(code, _req, _rep);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private AuthCode getAuthCode(HttpServletRequest _req, HttpServletResponse _rep) {
|
protected void post(HttpServletRequest _req, HttpServletResponse _rep) {
|
||||||
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) {
|
private boolean isSecure(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 false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -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/logs/log.txt</file>
|
<file>/opt/tomcat/log/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>
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,37 @@
|
|||||||
|
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();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -4,14 +4,16 @@
|
|||||||
<groupId>com.lanternsoftware.currentmonitor</groupId>
|
<groupId>com.lanternsoftware.currentmonitor</groupId>
|
||||||
<artifactId>currentmonitor</artifactId>
|
<artifactId>currentmonitor</artifactId>
|
||||||
<name>currentmonitor</name>
|
<name>currentmonitor</name>
|
||||||
<version>1.0.0</version>
|
<version>1.1.0</version>
|
||||||
|
|
||||||
<properties>
|
<parent>
|
||||||
<maven.compiler.source>1.8</maven.compiler.source>
|
<groupId>com.lanternsoftware</groupId>
|
||||||
<maven.compiler.target>1.8</maven.compiler.target>
|
<artifactId>LanternPowerMonitor</artifactId>
|
||||||
</properties>
|
<version>1.0.0</version>
|
||||||
|
</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
@ -1,25 +1,24 @@
|
|||||||
G04 Layer: BoardOutline*
|
G04 Layer: BoardOutline*
|
||||||
G04 EasyEDA v6.4.0, 2020-07-14T23:16:01--5:00*
|
G04 EasyEDA v6.4.25, 2022-04-08T13:20:52--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 ,3 integer and 3 decimal *
|
G04 leading zeros omitted , absolute positions ,4 integer and 5 decimal *
|
||||||
%FSLAX33Y33*%
|
%FSLAX45Y45*%
|
||||||
%MOMM*%
|
%MOMM*%
|
||||||
G90*
|
|
||||||
G71D02*
|
|
||||||
|
|
||||||
%ADD10C,0.254000*%
|
%ADD10C,0.2540*%
|
||||||
G54D10*
|
D10*
|
||||||
G01X0Y56000D02*
|
X0Y0D02*
|
||||||
G01X64999Y56000D01*
|
G01*
|
||||||
G01X64999Y0D01*
|
X6499994Y0D01*
|
||||||
G01X64999Y0D02*
|
X6499994Y-5600006D01*
|
||||||
G01X0Y0D01*
|
X6499994Y-5600006D02*
|
||||||
G01X0Y0D02*
|
G01*
|
||||||
G01X0Y56000D01*
|
X0Y-5600006D01*
|
||||||
|
X0Y-5600006D02*
|
||||||
|
G01*
|
||||||
|
X0Y0D01*
|
||||||
|
|
||||||
%LPD*%
|
%LPD*%
|
||||||
M00*
|
|
||||||
M02*
|
M02*
|
||||||
|
@ -1,382 +1,568 @@
|
|||||||
G04 Layer: BottomLayer*
|
G04 Layer: BottomLayer*
|
||||||
G04 EasyEDA v6.4.0, 2020-07-14T23:16:01--5:00*
|
G04 EasyEDA v6.4.25, 2022-04-08T13:20:52--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 ,3 integer and 3 decimal *
|
G04 leading zeros omitted , absolute positions ,4 integer and 5 decimal *
|
||||||
%FSLAX33Y33*%
|
%FSLAX45Y45*%
|
||||||
%MOMM*%
|
%MOMM*%
|
||||||
G90*
|
|
||||||
G71D02*
|
|
||||||
|
|
||||||
%ADD10C,0.254000*%
|
%ADD10C,0.2540*%
|
||||||
%ADD12C,0.609600*%
|
%ADD12C,0.6096*%
|
||||||
%ADD13R,1.799996X1.799996*%
|
%ADD13R,1.8000X1.8000*%
|
||||||
%ADD14C,1.799996*%
|
%ADD14C,1.2000*%
|
||||||
%ADD15C,1.199998*%
|
%ADD15C,1.5240*%
|
||||||
%ADD16C,1.524000*%
|
%ADD16C,1.8000*%
|
||||||
%ADD17C,1.599997*%
|
%ADD17C,1.6000*%
|
||||||
|
|
||||||
%LPD*%
|
%LPD*%
|
||||||
G54D10*
|
D10*
|
||||||
G01X8369Y53769D02*
|
X1545081Y-4261865D02*
|
||||||
G01X9639Y52499D01*
|
G01*
|
||||||
G01X11674Y52500D01*
|
X2353056Y-4261865D01*
|
||||||
G01X12174Y52000D01*
|
X2435097Y-4180077D01*
|
||||||
G01X12174Y48875D01*
|
X3668999Y-2127001D02*
|
||||||
G01X12999Y48141D01*
|
G01*
|
||||||
G01X12999Y47031D01*
|
X3303000Y-2127001D01*
|
||||||
G01X59499Y21125D02*
|
X3300001Y-2130000D01*
|
||||||
G01X59499Y21250D01*
|
X1299972Y-1927097D02*
|
||||||
G01X58750Y21999D01*
|
G01*
|
||||||
G01X51501Y21999D01*
|
X1299972Y-2769107D01*
|
||||||
G01X50250Y23250D01*
|
X1299997Y-2768983D02*
|
||||||
G01X50250Y34000D01*
|
G01*
|
||||||
G01X46979Y37270D01*
|
X1299997Y-3045007D01*
|
||||||
G01X44310Y37270D01*
|
X2434991Y-4180001D01*
|
||||||
G01X59500Y12124D02*
|
X3199993Y-1754997D02*
|
||||||
G01X59500Y12250D01*
|
G01*
|
||||||
G01X58000Y13750D01*
|
X3317996Y-1873001D01*
|
||||||
G01X51499Y13750D01*
|
X3668999Y-1873001D01*
|
||||||
G01X48749Y16500D01*
|
X3050031Y-1754631D02*
|
||||||
G01X48749Y32500D01*
|
G01*
|
||||||
G01X46519Y34730D01*
|
X3049993Y-1931995D01*
|
||||||
G01X44310Y34730D01*
|
X2831000Y-2127001D01*
|
||||||
G01X38874Y5499D02*
|
X2831084Y-2126995D01*
|
||||||
G01X38874Y6124D01*
|
X3630929Y-223012D02*
|
||||||
G01X46250Y13500D01*
|
G01*
|
||||||
G01X46250Y28750D01*
|
X3757993Y-348000D01*
|
||||||
G01X45349Y29650D01*
|
X3757993Y-659998D01*
|
||||||
G01X44310Y29650D01*
|
X3999991Y-899921D01*
|
||||||
G01X47873Y5499D02*
|
X3999991Y-1249934D01*
|
||||||
G01X47500Y5499D01*
|
X3884929Y-1364995D01*
|
||||||
G01X45999Y7000D01*
|
X3669029Y-1364995D01*
|
||||||
G01X45999Y10749D01*
|
X3669035Y-1618995D02*
|
||||||
G01X47500Y12251D01*
|
G01*
|
||||||
G01X47500Y30749D01*
|
X3668044Y-1618005D01*
|
||||||
G01X46060Y32190D01*
|
X3121990Y-1618005D01*
|
||||||
G01X44310Y32190D01*
|
X3121913Y-1617979D02*
|
||||||
G01X59499Y30125D02*
|
G01*
|
||||||
G01X59499Y30249D01*
|
X3121992Y-2249995D01*
|
||||||
G01X57749Y31999D01*
|
X2987995Y-2381994D01*
|
||||||
G01X55250Y31999D01*
|
X2831084Y-2380995D01*
|
||||||
G01X47439Y39810D01*
|
X3376929Y-477012D02*
|
||||||
G01X44310Y39810D01*
|
G01*
|
||||||
G01X59500Y39124D02*
|
X3377994Y-629998D01*
|
||||||
G01X59500Y39250D01*
|
X3050001Y-940000D01*
|
||||||
G01X57749Y41000D01*
|
X3050001Y-1754728D01*
|
||||||
G01X53750Y41000D01*
|
X5950000Y-787527D02*
|
||||||
G01X52399Y42350D01*
|
G01*
|
||||||
G01X44310Y42350D01*
|
X5950000Y-774999D01*
|
||||||
G01X59500Y48124D02*
|
X5850000Y-674999D01*
|
||||||
G01X59500Y48250D01*
|
X5375000Y-674999D01*
|
||||||
G01X58500Y49250D01*
|
X4939004Y-1110995D01*
|
||||||
G01X53750Y49250D01*
|
X4431004Y-1110995D01*
|
||||||
G01X49390Y44890D01*
|
X5950000Y-1687525D02*
|
||||||
G01X44310Y44890D01*
|
G01*
|
||||||
G01X33769Y51229D02*
|
X5950000Y-1675000D01*
|
||||||
G01X33779Y49700D01*
|
X5774999Y-1499999D01*
|
||||||
G01X30500Y46600D01*
|
X5375000Y-1499999D01*
|
||||||
G01X30500Y38452D01*
|
X5239997Y-1364995D01*
|
||||||
G01X31219Y39820D02*
|
X4431004Y-1364995D01*
|
||||||
G01X31219Y33500D01*
|
X5949950Y-2587497D02*
|
||||||
G01X29879Y32180D01*
|
G01*
|
||||||
G01X28310Y32190D01*
|
X5949950Y-2575052D01*
|
||||||
G01X36690Y39810D02*
|
X5774943Y-2400045D01*
|
||||||
G01X36680Y39820D01*
|
X5525008Y-2400045D01*
|
||||||
G01X31219Y39820D01*
|
X4743958Y-1618995D01*
|
||||||
G01X36309Y53769D02*
|
X4431029Y-1618995D01*
|
||||||
G01X37579Y52520D01*
|
X4787391Y-5050027D02*
|
||||||
G01X37579Y49400D01*
|
G01*
|
||||||
G01X39999Y47000D01*
|
X4750054Y-5050027D01*
|
||||||
G01X39999Y43500D01*
|
X4599940Y-4899913D01*
|
||||||
G01X38849Y42350D01*
|
X4599940Y-4525009D01*
|
||||||
G01X36690Y42350D01*
|
X4750054Y-4374895D01*
|
||||||
G01X30500Y38453D02*
|
X4750054Y-2525013D01*
|
||||||
G01X30499Y36680D01*
|
X4606036Y-2380995D01*
|
||||||
G01X28310Y34730D01*
|
X4431029Y-2380995D01*
|
||||||
G01X28310Y34730D01*
|
X3887470Y-5050027D02*
|
||||||
G01X31999Y38450D02*
|
G01*
|
||||||
G01X33179Y37270D01*
|
X3887470Y-4987543D01*
|
||||||
G01X36689Y37270D01*
|
X4625086Y-4249927D01*
|
||||||
G01X12999Y28310D02*
|
X4625086Y-2724912D01*
|
||||||
G01X12999Y25549D01*
|
X4534915Y-2634995D01*
|
||||||
G01X24349Y14200D01*
|
X4431029Y-2634995D01*
|
||||||
G01X12999Y36729D02*
|
X5950000Y-4387517D02*
|
||||||
G01X12999Y28308D01*
|
G01*
|
||||||
G01X36689Y34730D02*
|
X5950000Y-4375000D01*
|
||||||
G01X33030Y34730D01*
|
X5800001Y-4225000D01*
|
||||||
G01X33000Y34700D01*
|
X5149999Y-4225000D01*
|
||||||
G01X15450Y13381D02*
|
X4874999Y-3949999D01*
|
||||||
G01X23530Y13381D01*
|
X4874999Y-2350000D01*
|
||||||
G01X24350Y14199D01*
|
X4651994Y-2126995D01*
|
||||||
G54D13*
|
X4431004Y-2126995D01*
|
||||||
G01X20690Y44890D03*
|
X5949950Y-3487420D02*
|
||||||
G01X20690Y42350D03*
|
G01*
|
||||||
G01X20690Y34730D03*
|
X5949950Y-3474974D01*
|
||||||
G01X20690Y32190D03*
|
X5875020Y-3400043D01*
|
||||||
G01X20690Y39810D03*
|
X5150104Y-3400043D01*
|
||||||
G01X20690Y37270D03*
|
X5025001Y-3274999D01*
|
||||||
G01X20690Y29650D03*
|
X5025001Y-2200000D01*
|
||||||
G01X20690Y27110D03*
|
X4697984Y-1872995D01*
|
||||||
G01X28310Y27110D03*
|
X4431029Y-1872995D01*
|
||||||
G01X28310Y29650D03*
|
X836929Y-223012D02*
|
||||||
G01X28310Y32190D03*
|
G01*
|
||||||
G01X28310Y34730D03*
|
X963929Y-350012D01*
|
||||||
G01X28310Y37270D03*
|
X1167498Y-349999D01*
|
||||||
G01X28310Y39810D03*
|
X1217498Y-399999D01*
|
||||||
G01X28310Y42350D03*
|
X1217498Y-712497D01*
|
||||||
G01X28310Y44890D03*
|
X1299972Y-785876D01*
|
||||||
G01X44310Y27110D03*
|
X1299972Y-896873D01*
|
||||||
G01X44310Y29650D03*
|
D13*
|
||||||
G01X44310Y37270D03*
|
G01*
|
||||||
G01X44310Y39810D03*
|
X2069007Y-1110995D03*
|
||||||
G01X44310Y32190D03*
|
G01*
|
||||||
G01X44310Y34730D03*
|
X2069007Y-1364995D03*
|
||||||
G01X44310Y42350D03*
|
G01*
|
||||||
G01X44310Y44890D03*
|
X2069007Y-2126995D03*
|
||||||
G01X36690Y44890D03*
|
G01*
|
||||||
G01X36690Y42350D03*
|
X2069007Y-2380995D03*
|
||||||
G01X36690Y39810D03*
|
G01*
|
||||||
G01X36690Y37270D03*
|
X2069007Y-1618995D03*
|
||||||
G01X36690Y34730D03*
|
G01*
|
||||||
G01X36690Y32190D03*
|
X2069007Y-1872995D03*
|
||||||
G01X36690Y29650D03*
|
G01*
|
||||||
G01X36690Y27110D03*
|
X2069007Y-2634995D03*
|
||||||
|
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*
|
||||||
G01X57529Y52130D02*
|
X5752998Y-386999D02*
|
||||||
G01X55729Y52130D01*
|
G01*
|
||||||
G01X55729Y50330D01*
|
X5572998Y-386999D01*
|
||||||
G01X57529Y50330D01*
|
X5572998Y-566999D01*
|
||||||
G01X57529Y52130D01*
|
X5752998Y-566999D01*
|
||||||
G37*
|
G37*
|
||||||
G54D14*
|
D16*
|
||||||
G01X56630Y53769D03*
|
G01*
|
||||||
G01X54090Y51229D03*
|
X5663006Y-223012D03*
|
||||||
G01X54090Y53769D03*
|
G01*
|
||||||
G01X51550Y51229D03*
|
X5409006Y-477012D03*
|
||||||
G01X51550Y53769D03*
|
G01*
|
||||||
G01X49010Y51229D03*
|
X5409006Y-223012D03*
|
||||||
G01X49010Y53769D03*
|
G01*
|
||||||
G01X46470Y51229D03*
|
X5155006Y-477012D03*
|
||||||
G01X46470Y53769D03*
|
G01*
|
||||||
G01X43930Y51229D03*
|
X5155006Y-223012D03*
|
||||||
G01X43930Y53769D03*
|
G01*
|
||||||
G01X41390Y51229D03*
|
X4901006Y-477012D03*
|
||||||
G01X41390Y53769D03*
|
G01*
|
||||||
G01X38850Y51229D03*
|
X4901006Y-223012D03*
|
||||||
G01X38850Y53769D03*
|
G01*
|
||||||
G01X36310Y51229D03*
|
X4647006Y-477012D03*
|
||||||
G01X36310Y53769D03*
|
G01*
|
||||||
G01X33770Y51229D03*
|
X4647006Y-223012D03*
|
||||||
G01X33770Y53769D03*
|
G01*
|
||||||
G01X31230Y51229D03*
|
X4393006Y-477012D03*
|
||||||
G01X31230Y53769D03*
|
G01*
|
||||||
G01X28690Y51229D03*
|
X4393006Y-223012D03*
|
||||||
G01X28690Y53769D03*
|
G01*
|
||||||
G01X26150Y51229D03*
|
X4139006Y-477012D03*
|
||||||
G01X26150Y53769D03*
|
G01*
|
||||||
G01X23610Y51229D03*
|
X4139006Y-223012D03*
|
||||||
G01X23610Y53769D03*
|
G01*
|
||||||
G01X21070Y51229D03*
|
X3885006Y-477012D03*
|
||||||
G01X21070Y53769D03*
|
G01*
|
||||||
G01X18530Y51229D03*
|
X3885006Y-223012D03*
|
||||||
G01X18530Y53769D03*
|
G01*
|
||||||
G01X15990Y51229D03*
|
X3631006Y-477012D03*
|
||||||
G01X15990Y53769D03*
|
G01*
|
||||||
G01X13450Y51229D03*
|
X3631006Y-223012D03*
|
||||||
G01X13450Y53769D03*
|
G01*
|
||||||
G01X10910Y51229D03*
|
X3377006Y-477012D03*
|
||||||
G01X10910Y53769D03*
|
G01*
|
||||||
G01X8370Y51229D03*
|
X3377006Y-223012D03*
|
||||||
G01X8370Y53769D03*
|
G01*
|
||||||
G54D15*
|
X3123006Y-477012D03*
|
||||||
G01X49999Y19000D03*
|
G01*
|
||||||
G01X51500Y19000D03*
|
X3123006Y-223012D03*
|
||||||
G54D16*
|
G01*
|
||||||
G01X12999Y36730D03*
|
X2869006Y-477012D03*
|
||||||
G01X12999Y47030D03*
|
G01*
|
||||||
G01X52539Y27390D03*
|
X2869006Y-223012D03*
|
||||||
G01X52539Y37690D03*
|
G01*
|
||||||
G01X42249Y23900D03*
|
X2615006Y-477012D03*
|
||||||
G01X52550Y23900D03*
|
G01*
|
||||||
G01X12999Y18010D03*
|
X2615006Y-223012D03*
|
||||||
G01X12999Y28310D03*
|
G01*
|
||||||
G54D15*
|
X2361006Y-477012D03*
|
||||||
G01X13949Y13380D03*
|
G01*
|
||||||
G01X15450Y13380D03*
|
X2361006Y-223012D03*
|
||||||
G54D16*
|
G01*
|
||||||
G01X39600Y12549D03*
|
X2107006Y-477012D03*
|
||||||
G01X39600Y22850D03*
|
G01*
|
||||||
G01X24349Y14200D03*
|
X2107006Y-223012D03*
|
||||||
G01X34650Y14200D03*
|
G01*
|
||||||
G54D12*
|
X1853006Y-477012D03*
|
||||||
G01X31219Y39820D03*
|
G01*
|
||||||
G01X32999Y34700D03*
|
X1853006Y-223012D03*
|
||||||
G01X31999Y38450D03*
|
G01*
|
||||||
G01X30500Y38452D03*
|
X1599006Y-477012D03*
|
||||||
G01X36699Y25000D03*
|
G01*
|
||||||
G54D17*
|
X1599006Y-223012D03*
|
||||||
G01X32050Y22424D02*
|
G01*
|
||||||
G01X32950Y22424D01*
|
X1345006Y-477012D03*
|
||||||
G01X28600Y21225D02*
|
G01*
|
||||||
G01X28600Y22125D01*
|
X1345006Y-223012D03*
|
||||||
G01X30000Y18624D02*
|
G01*
|
||||||
G01X30000Y17724D01*
|
X1091006Y-477012D03*
|
||||||
G01X35000Y18624D02*
|
G01*
|
||||||
G01X35000Y17724D01*
|
X1091006Y-223012D03*
|
||||||
G01X36399Y22125D02*
|
G01*
|
||||||
G01X36399Y21225D01*
|
X837006Y-477012D03*
|
||||||
G01X5050Y48124D02*
|
G01*
|
||||||
G01X5950Y48124D01*
|
X837006Y-223012D03*
|
||||||
G01X1600Y46924D02*
|
D12*
|
||||||
G01X1600Y47824D01*
|
G01*
|
||||||
G01X3000Y44324D02*
|
X3121990Y-1618005D03*
|
||||||
G01X3000Y43424D01*
|
G01*
|
||||||
G01X8000Y44324D02*
|
X3299993Y-2129993D03*
|
||||||
G01X8000Y43424D01*
|
G01*
|
||||||
G01X9400Y47824D02*
|
X3199993Y-1754987D03*
|
||||||
G01X9400Y46924D01*
|
G01*
|
||||||
G01X5050Y39124D02*
|
X3050006Y-1754733D03*
|
||||||
G01X5950Y39124D01*
|
G01*
|
||||||
G01X1600Y37924D02*
|
X3669995Y-3099993D03*
|
||||||
G01X1600Y38824D01*
|
D17*
|
||||||
G01X3000Y35324D02*
|
X3205007Y-3357524D02*
|
||||||
G01X3000Y34424D01*
|
G01*
|
||||||
G01X8000Y35324D02*
|
X3295007Y-3357524D01*
|
||||||
G01X8000Y34424D01*
|
X2860014Y-3477503D02*
|
||||||
G01X9400Y38824D02*
|
G01*
|
||||||
G01X9400Y37924D01*
|
X2860014Y-3387506D01*
|
||||||
G01X5050Y30124D02*
|
X3000019Y-3737518D02*
|
||||||
G01X5950Y30124D01*
|
G01*
|
||||||
G01X1600Y28925D02*
|
X3000019Y-3827515D01*
|
||||||
G01X1600Y29825D01*
|
X3500018Y-3737518D02*
|
||||||
G01X3000Y26324D02*
|
G01*
|
||||||
G01X3000Y25424D01*
|
X3500018Y-3827515D01*
|
||||||
G01X8000Y26324D02*
|
X3639997Y-3387506D02*
|
||||||
G01X8000Y25424D01*
|
G01*
|
||||||
G01X9400Y29825D02*
|
X3639997Y-3477503D01*
|
||||||
G01X9400Y28925D01*
|
X505012Y-787527D02*
|
||||||
G01X5050Y21124D02*
|
G01*
|
||||||
G01X5950Y21124D01*
|
X595012Y-787527D01*
|
||||||
G01X1600Y19925D02*
|
X160020Y-907508D02*
|
||||||
G01X1600Y20825D01*
|
G01*
|
||||||
G01X3000Y17324D02*
|
X160020Y-817509D01*
|
||||||
G01X3000Y16424D01*
|
X300024Y-1167521D02*
|
||||||
G01X8000Y17324D02*
|
G01*
|
||||||
G01X8000Y16424D01*
|
X300024Y-1257520D01*
|
||||||
G01X9400Y20825D02*
|
X800023Y-1167521D02*
|
||||||
G01X9400Y19925D01*
|
G01*
|
||||||
G01X5050Y12124D02*
|
X800023Y-1257520D01*
|
||||||
G01X5950Y12124D01*
|
X940003Y-817509D02*
|
||||||
G01X1600Y10925D02*
|
G01*
|
||||||
G01X1600Y11825D01*
|
X940003Y-907508D01*
|
||||||
G01X3000Y8324D02*
|
X505012Y-1687525D02*
|
||||||
G01X3000Y7424D01*
|
G01*
|
||||||
G01X8000Y8324D02*
|
X595012Y-1687525D01*
|
||||||
G01X8000Y7424D01*
|
X160020Y-1807507D02*
|
||||||
G01X9400Y11825D02*
|
G01*
|
||||||
G01X9400Y10925D01*
|
X160020Y-1717507D01*
|
||||||
G01X59050Y48124D02*
|
X300024Y-2067519D02*
|
||||||
G01X59950Y48124D01*
|
G01*
|
||||||
G01X55600Y46924D02*
|
X300024Y-2157519D01*
|
||||||
G01X55600Y47824D01*
|
X800023Y-2067519D02*
|
||||||
G01X57000Y44324D02*
|
G01*
|
||||||
G01X57000Y43424D01*
|
X800023Y-2157519D01*
|
||||||
G01X62000Y44324D02*
|
X940003Y-1717507D02*
|
||||||
G01X62000Y43424D01*
|
G01*
|
||||||
G01X63399Y47824D02*
|
X940003Y-1807507D01*
|
||||||
G01X63399Y46924D01*
|
X505012Y-2587523D02*
|
||||||
G01X59050Y39124D02*
|
G01*
|
||||||
G01X59950Y39124D01*
|
X595012Y-2587523D01*
|
||||||
G01X55600Y37924D02*
|
X160020Y-2707505D02*
|
||||||
G01X55600Y38824D01*
|
G01*
|
||||||
G01X57000Y35324D02*
|
X160020Y-2617505D01*
|
||||||
G01X57000Y34424D01*
|
X300024Y-2967517D02*
|
||||||
G01X62000Y35324D02*
|
G01*
|
||||||
G01X62000Y34424D01*
|
X300024Y-3057517D01*
|
||||||
G01X63399Y38824D02*
|
X800023Y-2967517D02*
|
||||||
G01X63399Y37924D01*
|
G01*
|
||||||
G01X59050Y30124D02*
|
X800023Y-3057517D01*
|
||||||
G01X59950Y30124D01*
|
X940003Y-2617505D02*
|
||||||
G01X55600Y28925D02*
|
G01*
|
||||||
G01X55600Y29825D01*
|
X940003Y-2707505D01*
|
||||||
G01X57000Y26324D02*
|
X505012Y-3487521D02*
|
||||||
G01X57000Y25424D01*
|
G01*
|
||||||
G01X62000Y26324D02*
|
X595012Y-3487521D01*
|
||||||
G01X62000Y25424D01*
|
X160020Y-3607503D02*
|
||||||
G01X63399Y29825D02*
|
G01*
|
||||||
G01X63399Y28925D01*
|
X160020Y-3517503D01*
|
||||||
G01X59050Y21124D02*
|
X300024Y-3867515D02*
|
||||||
G01X59950Y21124D01*
|
G01*
|
||||||
G01X55600Y19925D02*
|
X300024Y-3957515D01*
|
||||||
G01X55600Y20825D01*
|
X800023Y-3867515D02*
|
||||||
G01X57000Y17324D02*
|
G01*
|
||||||
G01X57000Y16424D01*
|
X800023Y-3957515D01*
|
||||||
G01X62000Y17324D02*
|
X940003Y-3517503D02*
|
||||||
G01X62000Y16424D01*
|
G01*
|
||||||
G01X63399Y20825D02*
|
X940003Y-3607503D01*
|
||||||
G01X63399Y19925D01*
|
X505012Y-4387519D02*
|
||||||
G01X59050Y12124D02*
|
G01*
|
||||||
G01X59950Y12124D01*
|
X595012Y-4387519D01*
|
||||||
G01X55600Y10925D02*
|
X160020Y-4507501D02*
|
||||||
G01X55600Y11825D01*
|
G01*
|
||||||
G01X57000Y8324D02*
|
X160020Y-4417501D01*
|
||||||
G01X57000Y7424D01*
|
X300024Y-4767513D02*
|
||||||
G01X62000Y8324D02*
|
G01*
|
||||||
G01X62000Y7424D01*
|
X300024Y-4857513D01*
|
||||||
G01X63399Y11825D02*
|
X800023Y-4767513D02*
|
||||||
G01X63399Y10925D01*
|
G01*
|
||||||
G01X11875Y5050D02*
|
X800023Y-4857513D01*
|
||||||
G01X11875Y5950D01*
|
X940003Y-4417501D02*
|
||||||
G01X13075Y1600D02*
|
G01*
|
||||||
G01X12175Y1600D01*
|
X940003Y-4507501D01*
|
||||||
G01X15675Y3000D02*
|
X5905002Y-787527D02*
|
||||||
G01X16575Y3000D01*
|
G01*
|
||||||
G01X15675Y8000D02*
|
X5995001Y-787527D01*
|
||||||
G01X16575Y8000D01*
|
X5560009Y-907508D02*
|
||||||
G01X12175Y9399D02*
|
G01*
|
||||||
G01X13075Y9399D01*
|
X5560009Y-817509D01*
|
||||||
G01X20875Y5050D02*
|
X5700013Y-1167521D02*
|
||||||
G01X20875Y5950D01*
|
G01*
|
||||||
G01X22075Y1600D02*
|
X5700013Y-1257520D01*
|
||||||
G01X21175Y1600D01*
|
X6200013Y-1167521D02*
|
||||||
G01X24675Y3000D02*
|
G01*
|
||||||
G01X25575Y3000D01*
|
X6200013Y-1257520D01*
|
||||||
G01X24675Y8000D02*
|
X6339992Y-817509D02*
|
||||||
G01X25575Y8000D01*
|
G01*
|
||||||
G01X21175Y9399D02*
|
X6339992Y-907508D01*
|
||||||
G01X22075Y9399D01*
|
X5905002Y-1687525D02*
|
||||||
G01X29875Y5050D02*
|
G01*
|
||||||
G01X29875Y5950D01*
|
X5995001Y-1687525D01*
|
||||||
G01X31075Y1600D02*
|
X5560009Y-1807507D02*
|
||||||
G01X30175Y1600D01*
|
G01*
|
||||||
G01X33675Y3000D02*
|
X5560009Y-1717507D01*
|
||||||
G01X34575Y3000D01*
|
X5700013Y-2067519D02*
|
||||||
G01X33675Y8000D02*
|
G01*
|
||||||
G01X34575Y8000D01*
|
X5700013Y-2157519D01*
|
||||||
G01X30175Y9399D02*
|
X6200013Y-2067519D02*
|
||||||
G01X31075Y9399D01*
|
G01*
|
||||||
G01X38875Y5050D02*
|
X6200013Y-2157519D01*
|
||||||
G01X38875Y5950D01*
|
X6339992Y-1717507D02*
|
||||||
G01X40075Y1600D02*
|
G01*
|
||||||
G01X39175Y1600D01*
|
X6339992Y-1807507D01*
|
||||||
G01X42675Y3000D02*
|
X5905002Y-2587523D02*
|
||||||
G01X43575Y3000D01*
|
G01*
|
||||||
G01X42675Y8000D02*
|
X5995001Y-2587523D01*
|
||||||
G01X43575Y8000D01*
|
X5560009Y-2707505D02*
|
||||||
G01X39175Y9399D02*
|
G01*
|
||||||
G01X40075Y9399D01*
|
X5560009Y-2617505D01*
|
||||||
G01X47875Y5050D02*
|
X5700013Y-2967517D02*
|
||||||
G01X47875Y5950D01*
|
G01*
|
||||||
G01X49074Y1600D02*
|
X5700013Y-3057517D01*
|
||||||
G01X48175Y1600D01*
|
X6200013Y-2967517D02*
|
||||||
G01X51675Y3000D02*
|
G01*
|
||||||
G01X52575Y3000D01*
|
X6200013Y-3057517D01*
|
||||||
G01X51675Y8000D02*
|
X6339992Y-2617505D02*
|
||||||
G01X52575Y8000D01*
|
G01*
|
||||||
G01X48175Y9399D02*
|
X6339992Y-2707505D01*
|
||||||
G01X49074Y9399D01*
|
X5905002Y-3487521D02*
|
||||||
M00*
|
G01*
|
||||||
|
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*
|
||||||
|
@ -1,84 +1,88 @@
|
|||||||
G04 Layer: BottomSilkLayer*
|
G04 Layer: BottomSilkLayer*
|
||||||
G04 EasyEDA v6.4.0, 2020-07-14T23:16:01--5:00*
|
G04 EasyEDA v6.4.25, 2022-04-08T13:20:52--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 ,3 integer and 3 decimal *
|
G04 leading zeros omitted , absolute positions ,4 integer and 5 decimal *
|
||||||
%FSLAX33Y33*%
|
%FSLAX45Y45*%
|
||||||
%MOMM*%
|
%MOMM*%
|
||||||
G90*
|
|
||||||
G71D02*
|
|
||||||
|
|
||||||
%ADD10C,0.254000*%
|
%ADD10C,0.2540*%
|
||||||
%ADD18C,0.152400*%
|
%ADD18C,0.1524*%
|
||||||
|
|
||||||
%LPD*%
|
%LPD*%
|
||||||
G54D10*
|
D18*
|
||||||
G01X57899Y49960D02*
|
X2956062Y-674636D02*
|
||||||
G01X57899Y55040D01*
|
G01*
|
||||||
G01X7099Y55040D01*
|
X2961259Y-664245D01*
|
||||||
G01X7099Y49960D01*
|
X2971650Y-653854D01*
|
||||||
G01X57899Y49960D01*
|
X2982038Y-648660D01*
|
||||||
G01X57899Y52500D02*
|
X3002821Y-648660D01*
|
||||||
G01X55359Y52500D01*
|
X3013212Y-653854D01*
|
||||||
G01X55359Y49960D01*
|
X3023603Y-664245D01*
|
||||||
G54D18*
|
X3028800Y-674636D01*
|
||||||
G01X29560Y49253D02*
|
X3033994Y-690224D01*
|
||||||
G01X29612Y49357D01*
|
X3033994Y-716201D01*
|
||||||
G01X29716Y49461D01*
|
X3028800Y-731786D01*
|
||||||
G01X29820Y49513D01*
|
X3023603Y-742177D01*
|
||||||
G01X30028Y49513D01*
|
X3013212Y-752568D01*
|
||||||
G01X30132Y49461D01*
|
X3002821Y-757763D01*
|
||||||
G01X30236Y49357D01*
|
X2982038Y-757763D01*
|
||||||
G01X30288Y49253D01*
|
X2971650Y-752568D01*
|
||||||
G01X30339Y49097D01*
|
X2961259Y-742177D01*
|
||||||
G01X30339Y48838D01*
|
X2956062Y-731786D01*
|
||||||
G01X30288Y48682D01*
|
X2956062Y-716201D01*
|
||||||
G01X30236Y48578D01*
|
X2982038Y-716201D02*
|
||||||
G01X30132Y48474D01*
|
G01*
|
||||||
G01X30028Y48422D01*
|
X2956062Y-716201D01*
|
||||||
G01X29820Y48422D01*
|
X2921772Y-648660D02*
|
||||||
G01X29716Y48474D01*
|
G01*
|
||||||
G01X29612Y48578D01*
|
X2921772Y-757763D01*
|
||||||
G01X29560Y48682D01*
|
X2921772Y-648660D02*
|
||||||
G01X29560Y48838D01*
|
G01*
|
||||||
G01X29820Y48838D02*
|
X2875013Y-648660D01*
|
||||||
G01X29560Y48838D01*
|
X2859427Y-653854D01*
|
||||||
G01X29217Y49513D02*
|
X2854231Y-659051D01*
|
||||||
G01X29217Y48422D01*
|
X2849036Y-669442D01*
|
||||||
G01X29217Y49513D02*
|
X2849036Y-685027D01*
|
||||||
G01X28750Y49513D01*
|
X2854231Y-695418D01*
|
||||||
G01X28594Y49461D01*
|
X2859427Y-700613D01*
|
||||||
G01X28542Y49409D01*
|
X2875013Y-705810D01*
|
||||||
G01X28490Y49305D01*
|
X2921772Y-705810D01*
|
||||||
G01X28490Y49149D01*
|
X2814746Y-648660D02*
|
||||||
G01X28542Y49045D01*
|
G01*
|
||||||
G01X28594Y48993D01*
|
X2814746Y-757763D01*
|
||||||
G01X28750Y48941D01*
|
X2749283Y-648660D02*
|
||||||
G01X29217Y48941D01*
|
G01*
|
||||||
G01X28147Y49513D02*
|
X2759674Y-653854D01*
|
||||||
G01X28147Y48422D01*
|
X2770065Y-664245D01*
|
||||||
G01X27492Y49513D02*
|
X2775259Y-674636D01*
|
||||||
G01X27596Y49461D01*
|
X2780456Y-690224D01*
|
||||||
G01X27700Y49357D01*
|
X2780456Y-716201D01*
|
||||||
G01X27752Y49253D01*
|
X2775259Y-731786D01*
|
||||||
G01X27804Y49097D01*
|
X2770065Y-742177D01*
|
||||||
G01X27804Y48838D01*
|
X2759674Y-752568D01*
|
||||||
G01X27752Y48682D01*
|
X2749283Y-757763D01*
|
||||||
G01X27700Y48578D01*
|
X2728501Y-757763D01*
|
||||||
G01X27596Y48474D01*
|
X2718109Y-752568D01*
|
||||||
G01X27492Y48422D01*
|
X2707718Y-742177D01*
|
||||||
G01X27285Y48422D01*
|
X2702524Y-731786D01*
|
||||||
G01X27181Y48474D01*
|
X2697330Y-716201D01*
|
||||||
G01X27077Y48578D01*
|
X2697330Y-690224D01*
|
||||||
G01X27025Y48682D01*
|
X2702524Y-674636D01*
|
||||||
G01X26973Y48838D01*
|
X2707718Y-664245D01*
|
||||||
G01X26973Y49097D01*
|
X2718109Y-653854D01*
|
||||||
G01X27025Y49253D01*
|
X2728501Y-648660D01*
|
||||||
G01X27077Y49357D01*
|
X2749283Y-648660D01*
|
||||||
G01X27181Y49461D01*
|
D10*
|
||||||
G01X27285Y49513D01*
|
X5789998Y-603999D02*
|
||||||
G01X27492Y49513D01*
|
G01*
|
||||||
M00*
|
X5789998Y-95999D01*
|
||||||
|
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
@ -1,36 +1,38 @@
|
|||||||
;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
|
||||||
;Holesize 1 = 1.301 METRIC
|
;FILE_FORMAT=3:3
|
||||||
|
;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 METRIC
|
;Holesize 2 = 2.751 mm
|
||||||
T02C2.751
|
T02C2.751
|
||||||
%
|
%
|
||||||
G05
|
G05
|
||||||
G90
|
G90
|
||||||
T01
|
T01
|
||||||
X+032500Y+017424
|
X032500Y-038575
|
||||||
X+005500Y+043124
|
X005500Y-012875
|
||||||
X+005500Y+034124
|
X005500Y-021875
|
||||||
X+005500Y+025124
|
X005500Y-030875
|
||||||
X+005500Y+016124
|
X005500Y-039875
|
||||||
X+005500Y+007124
|
X005500Y-048875
|
||||||
X+059500Y+043124
|
X059500Y-012875
|
||||||
X+059500Y+034124
|
X059500Y-021875
|
||||||
X+059500Y+025124
|
X059500Y-030875
|
||||||
X+059500Y+016124
|
X059500Y-039875
|
||||||
X+059500Y+007124
|
X059500Y-048875
|
||||||
X+016875Y+005500
|
X016875Y-050500
|
||||||
X+025875Y+005500
|
X025875Y-050500
|
||||||
X+034875Y+005500
|
X034875Y-050500
|
||||||
X+043875Y+005500
|
X043875Y-050500
|
||||||
X+052875Y+005500
|
X052875Y-050500
|
||||||
T02
|
T02
|
||||||
X+061500Y+052499
|
X061500Y-003500
|
||||||
X+061500Y+003500
|
X061500Y-052500
|
||||||
X+003500Y+052499
|
X003500Y-003500
|
||||||
X+003500Y+003500
|
X003500Y-052500
|
||||||
M30
|
M30
|
||||||
|
@ -1,198 +1,200 @@
|
|||||||
;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
|
||||||
;Holesize 1 = 0.305 METRIC
|
;FILE_FORMAT=3:3
|
||||||
|
;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 METRIC
|
;Holesize 2 = 0.800 mm
|
||||||
T02C0.800
|
T02C0.800
|
||||||
;Holesize 3 = 1.000 METRIC
|
;Holesize 3 = 1.000 mm
|
||||||
T03C1.000
|
T03C1.000
|
||||||
;Holesize 4 = 1.101 METRIC
|
;Holesize 4 = 1.101 mm
|
||||||
T04C1.101
|
T04C1.101
|
||||||
;Holesize 5 = 1.200 METRIC
|
;Holesize 5 = 1.200 mm
|
||||||
T05C1.200
|
T05C1.200
|
||||||
%
|
%
|
||||||
G05
|
G05
|
||||||
G90
|
G90
|
||||||
T01
|
T01
|
||||||
X+031219Y+039820
|
X031220Y-016180
|
||||||
X+032999Y+034700
|
X033000Y-021300
|
||||||
X+031999Y+038450
|
X032000Y-017550
|
||||||
X+030500Y+038452
|
X030500Y-017547
|
||||||
X+036699Y+025000
|
X036700Y-031000
|
||||||
T02
|
T02
|
||||||
X+032950Y+022425G85X+032049Y+022425
|
X032950Y-033575G85X032050Y-033575
|
||||||
X+028600Y+022125G85X+028600Y+021225
|
X028600Y-033875G85X028600Y-034775
|
||||||
X+030000Y+017725G85X+030000Y+018625
|
X030000Y-038275G85X030000Y-037375
|
||||||
X+035000Y+017725G85X+035000Y+018625
|
X035000Y-038275G85X035000Y-037375
|
||||||
X+036400Y+021225G85X+036400Y+022125
|
X036400Y-034775G85X036400Y-033875
|
||||||
X+049999Y+019000
|
X049999Y-037000
|
||||||
X+051500Y+019000
|
X051501Y-037000
|
||||||
X+013949Y+013380
|
X013949Y-042620
|
||||||
X+015450Y+013380
|
X015451Y-042620
|
||||||
X+005950Y+048125G85X+005049Y+048125
|
X005950Y-007875G85X005050Y-007875
|
||||||
X+001599Y+047825G85X+001599Y+046925
|
X001600Y-008175G85X001600Y-009075
|
||||||
X+002999Y+043425G85X+002999Y+044325
|
X003000Y-012575G85X003000Y-011675
|
||||||
X+007999Y+043425G85X+007999Y+044325
|
X008000Y-012575G85X008000Y-011675
|
||||||
X+009399Y+046925G85X+009399Y+047825
|
X009400Y-009075G85X009400Y-008175
|
||||||
X+005950Y+039125G85X+005049Y+039125
|
X005950Y-016875G85X005050Y-016875
|
||||||
X+001599Y+038825G85X+001599Y+037925
|
X001600Y-017175G85X001600Y-018075
|
||||||
X+002999Y+034425G85X+002999Y+035325
|
X003000Y-021575G85X003000Y-020675
|
||||||
X+007999Y+034425G85X+007999Y+035325
|
X008000Y-021575G85X008000Y-020675
|
||||||
X+009399Y+037925G85X+009399Y+038825
|
X009400Y-018075G85X009400Y-017175
|
||||||
X+005950Y+030125G85X+005049Y+030125
|
X005950Y-025875G85X005050Y-025875
|
||||||
X+001599Y+029825G85X+001599Y+028925
|
X001600Y-026175G85X001600Y-027075
|
||||||
X+002999Y+025425G85X+002999Y+026325
|
X003000Y-030575G85X003000Y-029675
|
||||||
X+007999Y+025425G85X+007999Y+026325
|
X008000Y-030575G85X008000Y-029675
|
||||||
X+009399Y+028925G85X+009399Y+029825
|
X009400Y-027075G85X009400Y-026175
|
||||||
X+005950Y+021125G85X+005049Y+021125
|
X005950Y-034875G85X005050Y-034875
|
||||||
X+001599Y+020825G85X+001599Y+019925
|
X001600Y-035175G85X001600Y-036075
|
||||||
X+002999Y+016425G85X+002999Y+017325
|
X003000Y-039575G85X003000Y-038675
|
||||||
X+007999Y+016425G85X+007999Y+017325
|
X008000Y-039575G85X008000Y-038675
|
||||||
X+009399Y+019925G85X+009399Y+020825
|
X009400Y-036075G85X009400Y-035175
|
||||||
X+005950Y+012125G85X+005049Y+012125
|
X005950Y-043875G85X005050Y-043875
|
||||||
X+001599Y+011825G85X+001599Y+010925
|
X001600Y-044175G85X001600Y-045075
|
||||||
X+002999Y+007425G85X+002999Y+008325
|
X003000Y-048575G85X003000Y-047675
|
||||||
X+007999Y+007425G85X+007999Y+008325
|
X008000Y-048575G85X008000Y-047675
|
||||||
X+009399Y+010925G85X+009399Y+011825
|
X009400Y-045075G85X009400Y-044175
|
||||||
X+059950Y+048125G85X+059049Y+048125
|
X059950Y-007875G85X059050Y-007875
|
||||||
X+055600Y+047825G85X+055600Y+046925
|
X055600Y-008175G85X055600Y-009075
|
||||||
X+057000Y+043425G85X+057000Y+044325
|
X057000Y-012575G85X057000Y-011675
|
||||||
X+062000Y+043425G85X+062000Y+044325
|
X062000Y-012575G85X062000Y-011675
|
||||||
X+063400Y+046925G85X+063400Y+047825
|
X063400Y-009075G85X063400Y-008175
|
||||||
X+059950Y+039125G85X+059049Y+039125
|
X059950Y-016875G85X059050Y-016875
|
||||||
X+055600Y+038825G85X+055600Y+037925
|
X055600Y-017175G85X055600Y-018075
|
||||||
X+057000Y+034425G85X+057000Y+035325
|
X057000Y-021575G85X057000Y-020675
|
||||||
X+062000Y+034425G85X+062000Y+035325
|
X062000Y-021575G85X062000Y-020675
|
||||||
X+063400Y+037925G85X+063400Y+038825
|
X063400Y-018075G85X063400Y-017175
|
||||||
X+059950Y+030125G85X+059049Y+030125
|
X059950Y-025875G85X059050Y-025875
|
||||||
X+055600Y+029825G85X+055600Y+028925
|
X055600Y-026175G85X055600Y-027075
|
||||||
X+057000Y+025425G85X+057000Y+026325
|
X057000Y-030575G85X057000Y-029675
|
||||||
X+062000Y+025425G85X+062000Y+026325
|
X062000Y-030575G85X062000Y-029675
|
||||||
X+063400Y+028925G85X+063400Y+029825
|
X063400Y-027075G85X063400Y-026175
|
||||||
X+059950Y+021125G85X+059049Y+021125
|
X059950Y-034875G85X059050Y-034875
|
||||||
X+055600Y+020825G85X+055600Y+019925
|
X055600Y-035175G85X055600Y-036075
|
||||||
X+057000Y+016425G85X+057000Y+017325
|
X057000Y-039575G85X057000Y-038675
|
||||||
X+062000Y+016425G85X+062000Y+017325
|
X062000Y-039575G85X062000Y-038675
|
||||||
X+063400Y+019925G85X+063400Y+020825
|
X063400Y-036075G85X063400Y-035175
|
||||||
X+059950Y+012125G85X+059049Y+012125
|
X059950Y-043875G85X059050Y-043875
|
||||||
X+055600Y+011825G85X+055600Y+010925
|
X055600Y-044175G85X055600Y-045075
|
||||||
X+057000Y+007425G85X+057000Y+008325
|
X057000Y-048575G85X057000Y-047675
|
||||||
X+062000Y+007425G85X+062000Y+008325
|
X062000Y-048575G85X062000Y-047675
|
||||||
X+063400Y+010925G85X+063400Y+011825
|
X063400Y-045075G85X063400Y-044175
|
||||||
X+011874Y+005950G85X+011874Y+005050
|
X011875Y-050050G85X011875Y-050950
|
||||||
X+012174Y+001600G85X+013074Y+001600
|
X012175Y-054400G85X013075Y-054400
|
||||||
X+016574Y+003000G85X+015674Y+003000
|
X016575Y-053000G85X015675Y-053000
|
||||||
X+016574Y+008000G85X+015674Y+008000
|
X016575Y-048000G85X015675Y-048000
|
||||||
X+013074Y+009400G85X+012174Y+009400
|
X013075Y-046600G85X012175Y-046600
|
||||||
X+020874Y+005950G85X+020874Y+005050
|
X020875Y-050050G85X020875Y-050950
|
||||||
X+021174Y+001600G85X+022074Y+001600
|
X021175Y-054400G85X022075Y-054400
|
||||||
X+025575Y+003000G85X+024674Y+003000
|
X025575Y-053000G85X024675Y-053000
|
||||||
X+025575Y+008000G85X+024674Y+008000
|
X025575Y-048000G85X024675Y-048000
|
||||||
X+022074Y+009400G85X+021174Y+009400
|
X022075Y-046600G85X021175Y-046600
|
||||||
X+029874Y+005950G85X+029874Y+005050
|
X029875Y-050050G85X029875Y-050950
|
||||||
X+030174Y+001600G85X+031074Y+001600
|
X030175Y-054400G85X031075Y-054400
|
||||||
X+034575Y+003000G85X+033674Y+003000
|
X034575Y-053000G85X033675Y-053000
|
||||||
X+034575Y+008000G85X+033674Y+008000
|
X034575Y-048000G85X033675Y-048000
|
||||||
X+031074Y+009400G85X+030174Y+009400
|
X031075Y-046600G85X030175Y-046600
|
||||||
X+038874Y+005950G85X+038874Y+005050
|
X038875Y-050050G85X038875Y-050950
|
||||||
X+039174Y+001600G85X+040074Y+001600
|
X039175Y-054400G85X040075Y-054400
|
||||||
X+043574Y+003000G85X+042674Y+003000
|
X043575Y-053000G85X042675Y-053000
|
||||||
X+043574Y+008000G85X+042674Y+008000
|
X043575Y-048000G85X042675Y-048000
|
||||||
X+040074Y+009400G85X+039174Y+009400
|
X040075Y-046600G85X039175Y-046600
|
||||||
X+047874Y+005950G85X+047874Y+005050
|
X047875Y-050050G85X047875Y-050950
|
||||||
X+048174Y+001600G85X+049074Y+001600
|
X048175Y-054400G85X049075Y-054400
|
||||||
X+052575Y+003000G85X+051674Y+003000
|
X052575Y-053000G85X051675Y-053000
|
||||||
X+052575Y+008000G85X+051674Y+008000
|
X052575Y-048000G85X051675Y-048000
|
||||||
X+049074Y+009400G85X+048174Y+009400
|
X049075Y-046600G85X048175Y-046600
|
||||||
T03
|
T03
|
||||||
X+012999Y+036730
|
X013000Y-019270
|
||||||
X+012999Y+047030
|
X013000Y-008970
|
||||||
X+052539Y+027390
|
X052540Y-028610
|
||||||
X+052539Y+037690
|
X052540Y-018310
|
||||||
X+042250Y+023900
|
X042250Y-032100
|
||||||
X+052550Y+023900
|
X052550Y-032100
|
||||||
X+012999Y+018010
|
X013000Y-037990
|
||||||
X+012999Y+028310
|
X013000Y-027690
|
||||||
X+039600Y+012550
|
X039600Y-043450
|
||||||
X+039600Y+022850
|
X039600Y-033150
|
||||||
X+024350Y+014200
|
X024350Y-041800
|
||||||
X+034650Y+014200
|
X034650Y-041800
|
||||||
T04
|
T04
|
||||||
X+020690Y+044890
|
X020690Y-011110
|
||||||
X+020690Y+042350
|
X020690Y-013650
|
||||||
X+020690Y+034730
|
X020690Y-021270
|
||||||
X+020690Y+032190
|
X020690Y-023810
|
||||||
X+020690Y+039810
|
X020690Y-016190
|
||||||
X+020690Y+037270
|
X020690Y-018730
|
||||||
X+020690Y+029650
|
X020690Y-026350
|
||||||
X+020690Y+027110
|
X020690Y-028890
|
||||||
X+028310Y+027110
|
X028310Y-028890
|
||||||
X+028310Y+029650
|
X028310Y-026350
|
||||||
X+028310Y+032190
|
X028310Y-023810
|
||||||
X+028310Y+034730
|
X028310Y-021270
|
||||||
X+028310Y+037270
|
X028310Y-018730
|
||||||
X+028310Y+039810
|
X028310Y-016190
|
||||||
X+028310Y+042350
|
X028310Y-013650
|
||||||
X+028310Y+044890
|
X028310Y-011110
|
||||||
X+044309Y+027110
|
X044310Y-028890
|
||||||
X+044309Y+029650
|
X044310Y-026350
|
||||||
X+044309Y+037270
|
X044310Y-018730
|
||||||
X+044309Y+039810
|
X044310Y-016190
|
||||||
X+044309Y+032190
|
X044310Y-023810
|
||||||
X+044309Y+034730
|
X044310Y-021270
|
||||||
X+044309Y+042350
|
X044310Y-013650
|
||||||
X+044309Y+044890
|
X044310Y-011110
|
||||||
X+036689Y+044890
|
X036690Y-011110
|
||||||
X+036689Y+042350
|
X036690Y-013650
|
||||||
X+036689Y+039810
|
X036690Y-016190
|
||||||
X+036689Y+037270
|
X036690Y-018730
|
||||||
X+036689Y+034730
|
X036690Y-021270
|
||||||
X+036689Y+032190
|
X036690Y-023810
|
||||||
X+036689Y+029650
|
X036690Y-026350
|
||||||
X+036689Y+027110
|
X036690Y-028890
|
||||||
T05
|
T05
|
||||||
X+056630Y+051230
|
X056630Y-004770
|
||||||
X+056630Y+053770
|
X056630Y-002230
|
||||||
X+054090Y+051230
|
X054090Y-004770
|
||||||
X+054090Y+053770
|
X054090Y-002230
|
||||||
X+051550Y+051230
|
X051550Y-004770
|
||||||
X+051550Y+053770
|
X051550Y-002230
|
||||||
X+049010Y+051230
|
X049010Y-004770
|
||||||
X+049010Y+053770
|
X049010Y-002230
|
||||||
X+046470Y+051230
|
X046470Y-004770
|
||||||
X+046470Y+053770
|
X046470Y-002230
|
||||||
X+043930Y+051230
|
X043930Y-004770
|
||||||
X+043930Y+053770
|
X043930Y-002230
|
||||||
X+041390Y+051230
|
X041390Y-004770
|
||||||
X+041390Y+053770
|
X041390Y-002230
|
||||||
X+038850Y+051230
|
X038850Y-004770
|
||||||
X+038850Y+053770
|
X038850Y-002230
|
||||||
X+036310Y+051230
|
X036310Y-004770
|
||||||
X+036310Y+053770
|
X036310Y-002230
|
||||||
X+033770Y+051230
|
X033770Y-004770
|
||||||
X+033770Y+053770
|
X033770Y-002230
|
||||||
X+031230Y+051230
|
X031230Y-004770
|
||||||
X+031230Y+053770
|
X031230Y-002230
|
||||||
X+028690Y+051230
|
X028690Y-004770
|
||||||
X+028690Y+053770
|
X028690Y-002230
|
||||||
X+026150Y+051230
|
X026150Y-004770
|
||||||
X+026150Y+053770
|
X026150Y-002230
|
||||||
X+023610Y+051230
|
X023610Y-004770
|
||||||
X+023610Y+053770
|
X023610Y-002230
|
||||||
X+021070Y+051230
|
X021070Y-004770
|
||||||
X+021070Y+053770
|
X021070Y-002230
|
||||||
X+018530Y+051230
|
X018530Y-004770
|
||||||
X+018530Y+053770
|
X018530Y-002230
|
||||||
X+015990Y+051230
|
X015990Y-004770
|
||||||
X+015990Y+053770
|
X015990Y-002230
|
||||||
X+013450Y+051230
|
X013450Y-004770
|
||||||
X+013450Y+053770
|
X013450Y-002230
|
||||||
X+010910Y+051230
|
X010910Y-004770
|
||||||
X+010910Y+053770
|
X010910Y-002230
|
||||||
X+008370Y+051230
|
X008370Y-004770
|
||||||
X+008370Y+053770
|
X008370Y-002230
|
||||||
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
BIN
pcb/Gerber/LPMPCB.zip
Normal file
BIN
pcb/Gerber/LPMPCB.zip
Normal file
Binary file not shown.
68
pigpio/lantern-pigpio/pom.xml
Normal file
68
pigpio/lantern-pigpio/pom.xml
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
<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>
|
@ -0,0 +1,52 @@
|
|||||||
|
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);
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
54
pigpio/lantern-pigpio/src/main/native/Makefile
Normal file
54
pigpio/lantern-pigpio/src/main/native/Makefile
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
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
|
@ -0,0 +1,117 @@
|
|||||||
|
#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
Loading…
x
Reference in New Issue
Block a user