mirror of
https://github.com/zyphlar/LanternPowerMonitor.git
synced 2024-03-08 14:07:47 +00:00
Password reset functionality, ZWave switch schedule improvement, support zwave controller on pi, support relay switches and security sensors.
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -3,7 +3,7 @@
|
|||||||
<groupId>com.lanternsoftware.currentmonitor</groupId>
|
<groupId>com.lanternsoftware.currentmonitor</groupId>
|
||||||
<artifactId>lantern-currentmonitor</artifactId>
|
<artifactId>lantern-currentmonitor</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<version>1.0.2</version>
|
<version>1.0.4</version>
|
||||||
<name>lantern-currentmonitor</name>
|
<name>lantern-currentmonitor</name>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.pi4j</groupId>
|
<groupId>com.pi4j</groupId>
|
||||||
<artifactId>pi4j-gpio-extension</artifactId>
|
<artifactId>pi4j-gpio-extension</artifactId>
|
||||||
<version>1.2</version>
|
<version>1.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.hypfvieh</groupId>
|
<groupId>com.github.hypfvieh</groupId>
|
||||||
|
|||||||
+5
-5
@@ -178,14 +178,14 @@ public class MonitorApp {
|
|||||||
return new byte[]{NetworkMonitor.getNetworkStatus().toMask()};
|
return new byte[]{NetworkMonitor.getNetworkStatus().toMask()};
|
||||||
if (HubConfigCharacteristic.NetworkDetails == ch) {
|
if (HubConfigCharacteristic.NetworkDetails == ch) {
|
||||||
NetworkStatus status = NetworkMonitor.getNetworkStatus();
|
NetworkStatus status = NetworkMonitor.getNetworkStatus();
|
||||||
DaoEntity meta = DaoSerializer.fromZipBson(pool.executeToByteArray(new HttpGet(host + "update/version")));
|
DaoEntity meta = (host == null)?null:DaoSerializer.fromZipBson(pool.executeToByteArray(new HttpGet(host + "update/version")));
|
||||||
status.setPingSuccessful(CollectionUtils.isNotEmpty(meta));
|
status.setPingSuccessful(CollectionUtils.isNotEmpty(meta));
|
||||||
return DaoSerializer.toZipBson(status);
|
return DaoSerializer.toZipBson(status);
|
||||||
}
|
}
|
||||||
if (HubConfigCharacteristic.Log == ch) {
|
if (HubConfigCharacteristic.Log == ch) {
|
||||||
String[] log = NullUtils.cleanSplit(ResourceLoader.loadFileAsString(WORKING_DIR + "log/log.txt"), "\n");
|
String[] log = NullUtils.cleanSplit(ResourceLoader.loadFileAsString(WORKING_DIR + "log/log.txt"), "\n");
|
||||||
if (log.length > 10)
|
if (log.length > 15)
|
||||||
log = Arrays.copyOfRange(log, log.length-10, log.length);
|
log = Arrays.copyOfRange(log, log.length-15, log.length);
|
||||||
return ZipUtils.zip(NullUtils.toByteArray(CollectionUtils.delimit(Arrays.asList(log), "\n")));
|
return ZipUtils.zip(NullUtils.toByteArray(CollectionUtils.delimit(Arrays.asList(log), "\n")));
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -341,7 +341,7 @@ public class MonitorApp {
|
|||||||
if (files != null) {
|
if (files != null) {
|
||||||
for (File file : files) {
|
for (File file : files) {
|
||||||
payload = ResourceLoader.loadFile(file.getAbsolutePath());
|
payload = ResourceLoader.loadFile(file.getAbsolutePath());
|
||||||
if (post(payload, file.getName().endsWith("dat") ? "power/batch" : "power/hub"))
|
if (post(payload, "power/hub"))
|
||||||
file.delete();
|
file.delete();
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
@@ -401,7 +401,7 @@ public class MonitorApp {
|
|||||||
private static final class UpdateChecker implements Runnable {
|
private static final class UpdateChecker implements Runnable {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (NullUtils.isNotEmpty(host)) {
|
if (NullUtils.isNotEmpty(host) && config.isAutoUpdate()) {
|
||||||
DaoEntity meta = DaoSerializer.fromZipBson(pool.executeToByteArray(new HttpGet(host + "update/version")));
|
DaoEntity meta = DaoSerializer.fromZipBson(pool.executeToByteArray(new HttpGet(host + "update/version")));
|
||||||
String newVersion = DaoSerializer.getString(meta, "version");
|
String newVersion = DaoSerializer.getString(meta, "version");
|
||||||
if (NullUtils.isNotEqual(newVersion, version)) {
|
if (NullUtils.isNotEqual(newVersion, version)) {
|
||||||
|
|||||||
+9
@@ -17,6 +17,7 @@ public class MonitorConfig {
|
|||||||
private int connectTimeout;
|
private int connectTimeout;
|
||||||
private int socketTimeout;
|
private int socketTimeout;
|
||||||
private int updateInterval;
|
private int updateInterval;
|
||||||
|
private boolean autoUpdate;
|
||||||
private float autoCalibrationVoltage;
|
private float autoCalibrationVoltage;
|
||||||
private boolean needsCalibration;
|
private boolean needsCalibration;
|
||||||
private String mqttBrokerUrl;
|
private String mqttBrokerUrl;
|
||||||
@@ -107,6 +108,14 @@ public class MonitorConfig {
|
|||||||
updateInterval = _updateInterval;
|
updateInterval = _updateInterval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isAutoUpdate() {
|
||||||
|
return autoUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAutoUpdate(boolean _autoUpdate) {
|
||||||
|
autoUpdate = _autoUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
public float getAutoCalibrationVoltage() {
|
public float getAutoCalibrationVoltage() {
|
||||||
return autoCalibrationVoltage;
|
return autoCalibrationVoltage;
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -35,6 +35,7 @@ public class MonitorConfigSerializer extends AbstractDaoSerializer<MonitorConfig
|
|||||||
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("update_interval", _o.getUpdateInterval());
|
d.put("update_interval", _o.getUpdateInterval());
|
||||||
|
d.put("auto_update", _o.isAutoUpdate());
|
||||||
d.put("auto_calibration_voltage", _o.getAutoCalibrationVoltage());
|
d.put("auto_calibration_voltage", _o.getAutoCalibrationVoltage());
|
||||||
d.put("needs_calibration", _o.isNeedsCalibration());
|
d.put("needs_calibration", _o.isNeedsCalibration());
|
||||||
d.put("mqtt_broker_url", _o.getMqttBrokerUrl());
|
d.put("mqtt_broker_url", _o.getMqttBrokerUrl());
|
||||||
@@ -60,6 +61,7 @@ public class MonitorConfigSerializer extends AbstractDaoSerializer<MonitorConfig
|
|||||||
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.setUpdateInterval(DaoSerializer.getInteger(_d, "update_interval"));
|
o.setUpdateInterval(DaoSerializer.getInteger(_d, "update_interval"));
|
||||||
|
o.setAutoUpdate(DaoSerializer.getBoolean(_d, "auto_update"));
|
||||||
o.setAutoCalibrationVoltage(DaoSerializer.getFloat(_d, "auto_calibration_voltage"));
|
o.setAutoCalibrationVoltage(DaoSerializer.getFloat(_d, "auto_calibration_voltage"));
|
||||||
o.setNeedsCalibration(DaoSerializer.getBoolean(_d, "needs_calibration"));
|
o.setNeedsCalibration(DaoSerializer.getBoolean(_d, "needs_calibration"));
|
||||||
o.setMqttBrokerUrl(DaoSerializer.getString(_d, "mqtt_broker_url"));
|
o.setMqttBrokerUrl(DaoSerializer.getString(_d, "mqtt_broker_url"));
|
||||||
|
|||||||
+3
@@ -32,6 +32,9 @@ public interface CurrentMonitorDao {
|
|||||||
|
|
||||||
void updateSummaries(BreakerGroup _rootGroup, Set<Date> _daysToSummarize, TimeZone _tz);
|
void updateSummaries(BreakerGroup _rootGroup, Set<Date> _daysToSummarize, TimeZone _tz);
|
||||||
|
|
||||||
|
String addPasswordResetKey(String _email);
|
||||||
|
String getEmailForResetKey(String _key);
|
||||||
|
boolean resetPassword(String _key, String _password);
|
||||||
String authenticateAccount(String _username, String _password);
|
String authenticateAccount(String _username, String _password);
|
||||||
String getAuthCodeForEmail(String _email, TimeZone _tz);
|
String getAuthCodeForEmail(String _email, TimeZone _tz);
|
||||||
Account authCodeToAccount(String _authCode);
|
Account authCodeToAccount(String _authCode);
|
||||||
|
|||||||
+26
@@ -296,6 +296,32 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
|
|||||||
return _account;
|
return _account;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String addPasswordResetKey(String _email) {
|
||||||
|
String key = aes.encryptToBase64(_email);
|
||||||
|
proxy.saveEntity("password_reset", new DaoEntity("_id", key));
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getEmailForResetKey(String _key) {
|
||||||
|
DaoEntity entity = proxy.queryForEntity("password_reset", new DaoQuery("_id", _key));
|
||||||
|
if (entity == null)
|
||||||
|
return null;
|
||||||
|
return aes.decryptFromBase64ToString(_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean resetPassword(String _key, String _password) {
|
||||||
|
DaoEntity entity = proxy.queryForEntity("password_reset", new DaoQuery("_id", _key));
|
||||||
|
if (entity == null)
|
||||||
|
return false;
|
||||||
|
Account acct = getAccountByUsername(aes.decryptFromBase64ToString(_key));
|
||||||
|
acct.setPassword(_password);
|
||||||
|
putAccount(acct);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MongoProxy getProxy() {
|
public MongoProxy getProxy() {
|
||||||
return proxy;
|
return proxy;
|
||||||
|
|||||||
@@ -44,6 +44,11 @@
|
|||||||
<artifactId>logback-classic</artifactId>
|
<artifactId>logback-classic</artifactId>
|
||||||
<version>1.2.3</version>
|
<version>1.2.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sendgrid</groupId>
|
||||||
|
<artifactId>sendgrid-java</artifactId>
|
||||||
|
<version>4.7.2</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<build>
|
<build>
|
||||||
<resources>
|
<resources>
|
||||||
@@ -76,11 +81,25 @@
|
|||||||
<artifactId>maven-war-plugin</artifactId>
|
<artifactId>maven-war-plugin</artifactId>
|
||||||
<version>2.5</version>
|
<version>2.5</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
|
<webResources>
|
||||||
|
<resource>
|
||||||
|
<filtering>true</filtering>
|
||||||
|
<directory>src/main/webapp</directory>
|
||||||
|
<includes>
|
||||||
|
<include>versioninfo</include>
|
||||||
|
</includes>
|
||||||
|
</resource>
|
||||||
|
</webResources>
|
||||||
<archive>
|
<archive>
|
||||||
<manifest>
|
<manifest>
|
||||||
|
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
|
||||||
<addClasspath>true</addClasspath>
|
<addClasspath>true</addClasspath>
|
||||||
<classpathPrefix>lib/</classpathPrefix>
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
<manifestEntries>
|
||||||
|
<Build-Time>${maven.build.timestamp}</Build-Time>
|
||||||
|
<Build-OS>${os.name}</Build-OS>
|
||||||
|
<Implementation-Version>${project.version}</Implementation-Version>
|
||||||
|
</manifestEntries>
|
||||||
</archive>
|
</archive>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|||||||
+8
@@ -1,8 +1,11 @@
|
|||||||
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.dataaccess.currentmonitor.MongoCurrentMonitorDao;
|
||||||
import com.lanternsoftware.datamodel.currentmonitor.AuthCode;
|
import com.lanternsoftware.datamodel.currentmonitor.AuthCode;
|
||||||
import com.lanternsoftware.datamodel.currentmonitor.BreakerConfig;
|
import com.lanternsoftware.datamodel.currentmonitor.BreakerConfig;
|
||||||
|
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;
|
||||||
@@ -10,8 +13,13 @@ import javax.servlet.http.HttpServletResponse;
|
|||||||
|
|
||||||
@WebServlet("/config/*")
|
@WebServlet("/config/*")
|
||||||
public class ConfigServlet extends SecureServlet {
|
public class ConfigServlet extends SecureServlet {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(ConfigServlet.class);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void get(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
|
protected void get(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
|
||||||
|
if (_authCode.getAccountId() == 100) {
|
||||||
|
logger.error("my ip: " + _req.getRemoteAddr());
|
||||||
|
}
|
||||||
if (isPath(_req, 0, "bin"))
|
if (isPath(_req, 0, "bin"))
|
||||||
zipBsonResponse(_rep, Globals.dao.getMergedConfig(_authCode));
|
zipBsonResponse(_rep, Globals.dao.getMergedConfig(_authCode));
|
||||||
else
|
else
|
||||||
|
|||||||
+87
@@ -0,0 +1,87 @@
|
|||||||
|
package com.lanternsoftware.currentmonitor.servlet;
|
||||||
|
|
||||||
|
import com.lanternsoftware.currentmonitor.context.Globals;
|
||||||
|
import com.lanternsoftware.util.LanternFiles;
|
||||||
|
import com.lanternsoftware.util.NullUtils;
|
||||||
|
import com.lanternsoftware.util.ResourceLoader;
|
||||||
|
import com.lanternsoftware.util.dao.DaoEntity;
|
||||||
|
import com.lanternsoftware.util.dao.DaoSerializer;
|
||||||
|
import com.lanternsoftware.util.email.EmailValidator;
|
||||||
|
import com.lanternsoftware.util.servlet.FreemarkerConfigUtil;
|
||||||
|
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 org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import javax.servlet.annotation.WebServlet;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@WebServlet("/resetPassword/*")
|
||||||
|
public class ResetPasswordServlet extends FreemarkerServlet {
|
||||||
|
protected static final Logger LOG = LoggerFactory.getLogger(ResetPasswordServlet.class);
|
||||||
|
protected static final Configuration CONFIG = FreemarkerConfigUtil.createConfig(ResetPasswordServlet.class, "/templates", 100);
|
||||||
|
protected static final String api_key = ResourceLoader.loadFileAsString(LanternFiles.OPS_PATH + "sendgrid.txt");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Configuration getFreemarkerConfig() {
|
||||||
|
return CONFIG;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doGet(HttpServletRequest _req, HttpServletResponse _resp) {
|
||||||
|
String[] path = getPath(_req);
|
||||||
|
String email = Globals.dao.getEmailForResetKey(path[1]);
|
||||||
|
if (EmailValidator.getInstance().isValid(email)) {
|
||||||
|
render(_resp, "passwordReset.ftl", model(_req, "key", path[1]));
|
||||||
|
} else {
|
||||||
|
render(_resp, "passwordResetMsg.ftl", model(_req, "msg", "This password reset code is no longer valid. Please try sending a new code from the Lantern Power Monitor application."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doPost(HttpServletRequest _req, HttpServletResponse _resp) {
|
||||||
|
if (NullUtils.isEqual(_req.getContentType(), MediaType.APPLICATION_FORM_URLENCODED)) {
|
||||||
|
String key = _req.getParameter("reset_key");
|
||||||
|
String password = _req.getParameter("password");
|
||||||
|
if (NullUtils.length(password) < 8) {
|
||||||
|
render(_resp, "passwordReset.ftl", model(_req, "key", key).and("error", "Your password must be at least 8 characters."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Globals.dao.resetPassword(key, password);
|
||||||
|
render(_resp, "passwordResetMsg.ftl", model(_req, "msg", "Your password has been changed."));
|
||||||
|
} else {
|
||||||
|
DaoEntity payload = getRequestZipBson(_req);
|
||||||
|
String email = DaoSerializer.getString(payload, "email");
|
||||||
|
if (NullUtils.isNotEmpty(email)) {
|
||||||
|
String key = Globals.dao.addPasswordResetKey(email);
|
||||||
|
Email from = new Email("info@lanternsoftware.com");
|
||||||
|
String subject = "Password Reset - Lantern Power Monitor";
|
||||||
|
Email to = new Email(email);
|
||||||
|
Content content = new Content("text/plain", "Reset your password using this link:\nhttps://lanternsoftware.com/currentmonitor/resetPassword/" + key);
|
||||||
|
Mail mail = new Mail(from, subject, to, content);
|
||||||
|
SendGrid sg = new SendGrid(api_key);
|
||||||
|
Request request = new Request();
|
||||||
|
try {
|
||||||
|
request.setMethod(Method.POST);
|
||||||
|
request.setEndpoint("mail/send");
|
||||||
|
request.setBody(mail.build());
|
||||||
|
Response response = sg.api(request);
|
||||||
|
zipBsonResponse(_resp, new DaoEntity("success", response.getStatusCode() == 200));
|
||||||
|
} catch (IOException ex) {
|
||||||
|
LOG.error("Failed to send password reset email", ex);
|
||||||
|
zipBsonResponse(_resp, new DaoEntity("success", false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>Lantern | Reset Password</title>
|
||||||
|
<link href="${context}/bootstrap/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<section id="reset" class="container features" style="margin-top:40px;margin-bottom:40px;">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-12">
|
||||||
|
<div class="navy-line"></div>
|
||||||
|
<h4><img class="mr-1" src="${context}/img/logo_40.png">Reset Password</h4>
|
||||||
|
<form class="ml-2" method="POST">
|
||||||
|
<input type="hidden" name="reset_key" value="${key}"/>
|
||||||
|
<div>New Password:</div>
|
||||||
|
<input type="password" name="password"/>
|
||||||
|
<input type="submit" class="btn-primary" value="Submit"/>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>Lantern | Reset Password</title>
|
||||||
|
<link href="${context}/bootstrap/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<section id="reset" class="container features" style="margin-top:40px;margin-bottom:40px;">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-12">
|
||||||
|
<div class="navy-line"></div>
|
||||||
|
<h4><img class="mr-1" src="${context}/img/logo_40.png">Reset Password</h4>
|
||||||
|
<div class="ml-2">${msg}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Vendored
+3904
File diff suppressed because it is too large
Load Diff
+1
File diff suppressed because one or more lines are too long
Vendored
+7
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
Vendored
+325
@@ -0,0 +1,325 @@
|
|||||||
|
/*!
|
||||||
|
* Bootstrap Reboot v4.5.0 (https://getbootstrap.com/)
|
||||||
|
* Copyright 2011-2020 The Bootstrap Authors
|
||||||
|
* Copyright 2011-2020 Twitter, Inc.
|
||||||
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||||
|
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
||||||
|
*/
|
||||||
|
*,
|
||||||
|
*::before,
|
||||||
|
*::after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
font-family: sans-serif;
|
||||||
|
line-height: 1.15;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
article, aside, figcaption, figure, footer, header, hgroup, main, nav, section {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: #212529;
|
||||||
|
text-align: left;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
[tabindex="-1"]:focus:not(:focus-visible) {
|
||||||
|
outline: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
box-sizing: content-box;
|
||||||
|
height: 0;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
abbr[title],
|
||||||
|
abbr[data-original-title] {
|
||||||
|
text-decoration: underline;
|
||||||
|
-webkit-text-decoration: underline dotted;
|
||||||
|
text-decoration: underline dotted;
|
||||||
|
cursor: help;
|
||||||
|
border-bottom: 0;
|
||||||
|
-webkit-text-decoration-skip-ink: none;
|
||||||
|
text-decoration-skip-ink: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
address {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
font-style: normal;
|
||||||
|
line-height: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
ol,
|
||||||
|
ul,
|
||||||
|
dl {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
ol ol,
|
||||||
|
ul ul,
|
||||||
|
ol ul,
|
||||||
|
ul ol {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dt {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
dd {
|
||||||
|
margin-bottom: .5rem;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
margin: 0 0 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
b,
|
||||||
|
strong {
|
||||||
|
font-weight: bolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
small {
|
||||||
|
font-size: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub,
|
||||||
|
sup {
|
||||||
|
position: relative;
|
||||||
|
font-size: 75%;
|
||||||
|
line-height: 0;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub {
|
||||||
|
bottom: -.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
sup {
|
||||||
|
top: -.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #007bff;
|
||||||
|
text-decoration: none;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: #0056b3;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:not([href]) {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:not([href]):hover {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre,
|
||||||
|
code,
|
||||||
|
kbd,
|
||||||
|
samp {
|
||||||
|
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
overflow: auto;
|
||||||
|
-ms-overflow-style: scrollbar;
|
||||||
|
}
|
||||||
|
|
||||||
|
figure {
|
||||||
|
margin: 0 0 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
vertical-align: middle;
|
||||||
|
border-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
overflow: hidden;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
caption {
|
||||||
|
padding-top: 0.75rem;
|
||||||
|
padding-bottom: 0.75rem;
|
||||||
|
color: #6c757d;
|
||||||
|
text-align: left;
|
||||||
|
caption-side: bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
text-align: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: inline-block;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:focus {
|
||||||
|
outline: 1px dotted;
|
||||||
|
outline: 5px auto -webkit-focus-ring-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
input,
|
||||||
|
button,
|
||||||
|
select,
|
||||||
|
optgroup,
|
||||||
|
textarea {
|
||||||
|
margin: 0;
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
button,
|
||||||
|
input {
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
button,
|
||||||
|
select {
|
||||||
|
text-transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
[role="button"] {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
word-wrap: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
button,
|
||||||
|
[type="button"],
|
||||||
|
[type="reset"],
|
||||||
|
[type="submit"] {
|
||||||
|
-webkit-appearance: button;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:not(:disabled),
|
||||||
|
[type="button"]:not(:disabled),
|
||||||
|
[type="reset"]:not(:disabled),
|
||||||
|
[type="submit"]:not(:disabled) {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
button::-moz-focus-inner,
|
||||||
|
[type="button"]::-moz-focus-inner,
|
||||||
|
[type="reset"]::-moz-focus-inner,
|
||||||
|
[type="submit"]::-moz-focus-inner {
|
||||||
|
padding: 0;
|
||||||
|
border-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="radio"],
|
||||||
|
input[type="checkbox"] {
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
overflow: auto;
|
||||||
|
resize: vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset {
|
||||||
|
min-width: 0;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
legend {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
padding: 0;
|
||||||
|
margin-bottom: .5rem;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
line-height: inherit;
|
||||||
|
color: inherit;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
progress {
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
[type="number"]::-webkit-inner-spin-button,
|
||||||
|
[type="number"]::-webkit-outer-spin-button {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
[type="search"] {
|
||||||
|
outline-offset: -2px;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
[type="search"]::-webkit-search-decoration {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-file-upload-button {
|
||||||
|
font: inherit;
|
||||||
|
-webkit-appearance: button;
|
||||||
|
}
|
||||||
|
|
||||||
|
output {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
summary {
|
||||||
|
display: list-item;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
template {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
[hidden] {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
/*# sourceMappingURL=bootstrap-reboot.css.map */
|
||||||
+1
File diff suppressed because one or more lines are too long
currentmonitor/lantern-service-currentmonitor/src/main/webapp/bootstrap/css/bootstrap-reboot.min.css
Vendored
+8
@@ -0,0 +1,8 @@
|
|||||||
|
/*!
|
||||||
|
* Bootstrap Reboot v4.5.0 (https://getbootstrap.com/)
|
||||||
|
* Copyright 2011-2020 The Bootstrap Authors
|
||||||
|
* Copyright 2011-2020 Twitter, Inc.
|
||||||
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||||
|
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
||||||
|
*/*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus:not(:focus-visible){outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent}a:hover{color:#0056b3;text-decoration:underline}a:not([href]){color:inherit;text-decoration:none}a:not([href]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}
|
||||||
|
/*# sourceMappingURL=bootstrap-reboot.min.css.map */
|
||||||
+1
File diff suppressed because one or more lines are too long
+10278
File diff suppressed because it is too large
Load Diff
+1
File diff suppressed because one or more lines are too long
Vendored
+7
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
Vendored
+7033
File diff suppressed because it is too large
Load Diff
+1
File diff suppressed because one or more lines are too long
Vendored
+7
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+4420
File diff suppressed because it is too large
Load Diff
+1
File diff suppressed because one or more lines are too long
Vendored
+7
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.9 KiB |
@@ -80,6 +80,8 @@ public class HttpPool {
|
|||||||
CloseableHttpResponse resp = null;
|
CloseableHttpResponse resp = null;
|
||||||
try {
|
try {
|
||||||
resp = execute(_request);
|
resp = execute(_request);
|
||||||
|
if (resp == null)
|
||||||
|
return null;
|
||||||
if ((resp.getStatusLine().getStatusCode() < 200) || (resp.getStatusLine().getStatusCode() >= 300)) {
|
if ((resp.getStatusLine().getStatusCode() < 200) || (resp.getStatusLine().getStatusCode() >= 300)) {
|
||||||
LOG.error("Failed to make http request to " + _request.getURI().toString() + ". Status code: " + resp.getStatusLine().getStatusCode());
|
LOG.error("Failed to make http request to " + _request.getURI().toString() + ". Status code: " + resp.getStatusLine().getStatusCode());
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>${project.groupId}</groupId>
|
<groupId>${project.groupId}</groupId>
|
||||||
<artifactId>lantern-util-common</artifactId>
|
<artifactId>lantern-util-dao</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
+108
-59
@@ -1,27 +1,24 @@
|
|||||||
package com.lanternsoftware.util.servlet;
|
package com.lanternsoftware.util.servlet;
|
||||||
|
|
||||||
import java.io.IOException;
|
import com.lanternsoftware.util.CollectionUtils;
|
||||||
import java.io.OutputStream;
|
import com.lanternsoftware.util.NullUtils;
|
||||||
import java.util.HashMap;
|
import com.lanternsoftware.util.dao.DaoEntity;
|
||||||
import java.util.Map;
|
import com.lanternsoftware.util.dao.DaoSerializer;
|
||||||
|
import freemarker.template.Configuration;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
|
||||||
import javax.servlet.http.Cookie;
|
import javax.servlet.http.Cookie;
|
||||||
import javax.servlet.http.HttpServlet;
|
import javax.servlet.http.HttpServlet;
|
||||||
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 org.apache.commons.io.IOUtils;
|
import java.io.IOException;
|
||||||
import org.slf4j.Logger;
|
import java.io.InputStream;
|
||||||
import org.slf4j.LoggerFactory;
|
import java.io.OutputStream;
|
||||||
|
import java.util.HashMap;
|
||||||
import com.lanternsoftware.util.CollectionUtils;
|
import java.util.Map;
|
||||||
import com.lanternsoftware.util.NullUtils;
|
|
||||||
|
|
||||||
import freemarker.template.Configuration;
|
|
||||||
|
|
||||||
public abstract class FreemarkerServlet extends HttpServlet {
|
public abstract class FreemarkerServlet extends HttpServlet {
|
||||||
protected static final Logger LOG = LoggerFactory.getLogger(FreemarkerServlet.class);
|
|
||||||
|
|
||||||
protected abstract Configuration getFreemarkerConfig();
|
protected abstract Configuration getFreemarkerConfig();
|
||||||
|
|
||||||
public static String[] getPath(HttpServletRequest _request) {
|
public static String[] getPath(HttpServletRequest _request) {
|
||||||
@@ -29,7 +26,7 @@ public abstract class FreemarkerServlet extends HttpServlet {
|
|||||||
if (sPath.startsWith("/"))
|
if (sPath.startsWith("/"))
|
||||||
sPath = sPath.substring(1);
|
sPath = sPath.substring(1);
|
||||||
String[] path = sPath.split("/");
|
String[] path = sPath.split("/");
|
||||||
if ((path == null) || (path.length == 0) || (path[0].length() == 0))
|
if ((path.length == 0) || (path[0].length() == 0))
|
||||||
return new String[] { "index" };
|
return new String[] { "index" };
|
||||||
int iExtPos = CollectionUtils.last(path).lastIndexOf(".");
|
int iExtPos = CollectionUtils.last(path).lastIndexOf(".");
|
||||||
if (iExtPos > -1) {
|
if (iExtPos > -1) {
|
||||||
@@ -42,45 +39,6 @@ public abstract class FreemarkerServlet extends HttpServlet {
|
|||||||
_response.sendRedirect(_response.encodeRedirectURL(_sURL));
|
_response.sendRedirect(_response.encodeRedirectURL(_sURL));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setResponseHtml(HttpServletResponse _response, String _sHtml) {
|
|
||||||
setResponseEntity(_response, "text/html", _sHtml);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setResponseEntity(HttpServletResponse _response, String _sContentType, String _sEntity) {
|
|
||||||
setResponseEntity(_response, 200, _sContentType, _sEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setResponseEntity(HttpServletResponse _response, String _sContentType, byte[] _btData) {
|
|
||||||
setResponseEntity(_response, 200, _sContentType, _btData);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setResponseEntity(HttpServletResponse _response, int _iStatus, String _sContentType, String _sEntity) {
|
|
||||||
setResponseEntity(_response, _iStatus, _sContentType, NullUtils.toByteArray(_sEntity));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setResponseEntity(HttpServletResponse _response, int _iStatus, String _sContentType, byte[] _btData) {
|
|
||||||
OutputStream os = null;
|
|
||||||
try {
|
|
||||||
_response.setStatus(_iStatus);
|
|
||||||
_response.setCharacterEncoding("UTF-8");
|
|
||||||
_response.setContentType(_sContentType);
|
|
||||||
if ((_btData != null) && (_btData.length > 0)) {
|
|
||||||
_response.setContentLength(_btData.length);
|
|
||||||
os = _response.getOutputStream();
|
|
||||||
os.write(_btData);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
_response.setContentLength(0);
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
if (!e.getClass().getSimpleName().equals("ClientAbortException"))
|
|
||||||
LOG.error("Failed to set response entity", e);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
IOUtils.closeQuietly(os);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void render(HttpServletResponse _rep, String _sHtmlResourceKey, Map<String, Object> _mapModel) {
|
public void render(HttpServletResponse _rep, String _sHtmlResourceKey, Map<String, Object> _mapModel) {
|
||||||
String html = FreemarkerUtil.render(getFreemarkerConfig(), _sHtmlResourceKey, _mapModel);
|
String html = FreemarkerUtil.render(getFreemarkerConfig(), _sHtmlResourceKey, _mapModel);
|
||||||
if (html == null)
|
if (html == null)
|
||||||
@@ -89,10 +47,16 @@ public abstract class FreemarkerServlet extends HttpServlet {
|
|||||||
setResponseHtml(_rep, html);
|
setResponseHtml(_rep, html);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Map<String, Object> simpleModel(String _name, Object _value) {
|
public static DaoEntity model(HttpServletRequest _req, String _name, Object _value) {
|
||||||
Map<String, Object> mapModel = new HashMap<String, Object>();
|
DaoEntity model = model(_req);
|
||||||
mapModel.put(_name, _value);
|
model.put(_name, _value);
|
||||||
return mapModel;
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static DaoEntity model(HttpServletRequest _req) {
|
||||||
|
DaoEntity model = new DaoEntity("context", _req.getContextPath());
|
||||||
|
model.put("css_version", "1.0.0");
|
||||||
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> T getSessionVar(HttpServletRequest _req, String _name) {
|
public static <T> T getSessionVar(HttpServletRequest _req, String _name) {
|
||||||
@@ -122,4 +86,89 @@ public abstract class FreemarkerServlet extends HttpServlet {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void setResponseHtml(HttpServletResponse _response, String _sHtml) {
|
||||||
|
setResponseEntity(_response, MediaType.TEXT_HTML, _sHtml);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setResponseEntity(HttpServletResponse _response, String _sContentType, String _sEntity) {
|
||||||
|
setResponseEntity(_response, 200, _sContentType, _sEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setResponseEntity(HttpServletResponse _response, String _sContentType, byte[] _btData) {
|
||||||
|
setResponseEntity(_response, 200, _sContentType, _btData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setResponseEntity(HttpServletResponse _response, int _iStatus, String _sContentType, String _sEntity) {
|
||||||
|
setResponseEntity(_response, _iStatus, _sContentType, NullUtils.toByteArray(_sEntity));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setResponseEntity(HttpServletResponse _response, int _iStatus, String _sContentType, byte[] _btData) {
|
||||||
|
OutputStream os = null;
|
||||||
|
try {
|
||||||
|
_response.setStatus(_iStatus);
|
||||||
|
_response.setCharacterEncoding("UTF-8");
|
||||||
|
_response.setContentType(_sContentType);
|
||||||
|
if ((_btData != null) && (_btData.length > 0)) {
|
||||||
|
_response.setContentLength(_btData.length);
|
||||||
|
os = _response.getOutputStream();
|
||||||
|
os.write(_btData);
|
||||||
|
} else
|
||||||
|
_response.setContentLength(0);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
IOUtils.closeQuietly(os);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void zipBsonResponse(HttpServletResponse _response, Object _object)
|
||||||
|
{
|
||||||
|
setResponseEntity(_response, 200, MediaType.APPLICATION_OCTET_STREAM, DaoSerializer.toZipBson(_object));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void jsonResponse(HttpServletResponse _response, Object _object)
|
||||||
|
{
|
||||||
|
setResponseEntity(_response, 200, MediaType.APPLICATION_JSON, DaoSerializer.toJson(_object));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void jsonResponse(HttpServletResponse _response, String _json)
|
||||||
|
{
|
||||||
|
setResponseEntity(_response, 200, MediaType.APPLICATION_JSON, _json);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getRequestPayloadAsString(HttpServletRequest _req) {
|
||||||
|
return NullUtils.toString(getRequestPayload(_req));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected byte[] getRequestPayload(HttpServletRequest _req) {
|
||||||
|
InputStream is = null;
|
||||||
|
try {
|
||||||
|
is = _req.getInputStream();
|
||||||
|
return IOUtils.toByteArray(is);
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
IOUtils.closeQuietly(is);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected DaoEntity getRequestZipBson(HttpServletRequest _req) {
|
||||||
|
return DaoSerializer.fromZipBson(getRequestPayload(_req));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected <T> T getRequestPayload(HttpServletRequest _req, Class<T> _retClass) {
|
||||||
|
return DaoSerializer.fromZipBson(getRequestPayload(_req), _retClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String[] path(HttpServletRequest _req) {
|
||||||
|
return NullUtils.cleanSplit(NullUtils.makeNotNull(_req.getPathInfo()), "/");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isPath(HttpServletRequest _req, int _index, String _path) {
|
||||||
|
return NullUtils.isEqual(_path, CollectionUtils.get(path(_req), _index));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+104
-22
@@ -1,21 +1,26 @@
|
|||||||
package com.lanternsoftware.datamodel.zwave;
|
package com.lanternsoftware.datamodel.zwave;
|
||||||
|
|
||||||
|
|
||||||
|
import com.lanternsoftware.util.CollectionUtils;
|
||||||
import com.lanternsoftware.util.NullUtils;
|
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;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
@DBSerializable
|
@DBSerializable
|
||||||
public class Switch {
|
public class Switch {
|
||||||
|
private SwitchType type;
|
||||||
private String room;
|
private String room;
|
||||||
private String name;
|
private String name;
|
||||||
private int nodeId;
|
private int nodeId;
|
||||||
private int level;
|
private int level;
|
||||||
|
private int gpioPin;
|
||||||
private boolean primary;
|
private boolean primary;
|
||||||
private boolean multilevel;
|
|
||||||
private boolean hold;
|
private boolean hold;
|
||||||
private String thermostatSource;
|
private boolean hidden;
|
||||||
|
private String thermometerUrl;
|
||||||
|
private String controllerUrl;
|
||||||
private ThermostatMode thermostatMode;
|
private ThermostatMode thermostatMode;
|
||||||
private int lowLevel;
|
private int lowLevel;
|
||||||
private List<SwitchSchedule> schedule;
|
private List<SwitchSchedule> schedule;
|
||||||
@@ -23,23 +28,30 @@ public class Switch {
|
|||||||
public Switch() {
|
public Switch() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Switch(String _room, String _name, int _nodeId, boolean _primary, boolean _multilevel, String _thermostatSource, int _lowLevel) {
|
public Switch(String _room, String _name, int _nodeId, boolean _primary, boolean _multilevel, String _thermometerUrl, int _lowLevel) {
|
||||||
this(_room, _name, _nodeId, 0, _primary, _multilevel, false, _thermostatSource, _lowLevel, null);
|
this(_room, _name, _nodeId, 0, _primary, false, _thermometerUrl, _lowLevel, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Switch(String _room, String _name, int _nodeId, int _level, boolean _primary, boolean _multilevel, boolean _hold, String _thermostatSource, int _lowLevel, List<SwitchSchedule> _schedule) {
|
public Switch(String _room, String _name, int _nodeId, int _level, boolean _primary, boolean _hold, String _thermometerUrl, int _lowLevel, List<SwitchSchedule> _schedule) {
|
||||||
room = _room;
|
room = _room;
|
||||||
name = _name;
|
name = _name;
|
||||||
nodeId = _nodeId;
|
nodeId = _nodeId;
|
||||||
level = _level;
|
level = _level;
|
||||||
primary = _primary;
|
primary = _primary;
|
||||||
multilevel = _multilevel;
|
|
||||||
hold = _hold;
|
hold = _hold;
|
||||||
thermostatSource = _thermostatSource;
|
thermometerUrl = _thermometerUrl;
|
||||||
lowLevel = _lowLevel;
|
lowLevel = _lowLevel;
|
||||||
schedule = _schedule;
|
schedule = _schedule;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SwitchType getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(SwitchType _type) {
|
||||||
|
type = _type;
|
||||||
|
}
|
||||||
|
|
||||||
public String getRoom() {
|
public String getRoom() {
|
||||||
return room;
|
return room;
|
||||||
}
|
}
|
||||||
@@ -56,6 +68,12 @@ public class Switch {
|
|||||||
name = _name;
|
name = _name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getFullDisplay() {
|
||||||
|
if (NullUtils.isNotEmpty(room))
|
||||||
|
return room + " - " + name;
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
public int getNodeId() {
|
public int getNodeId() {
|
||||||
return nodeId;
|
return nodeId;
|
||||||
}
|
}
|
||||||
@@ -72,6 +90,14 @@ public class Switch {
|
|||||||
level = _level;
|
level = _level;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getGpioPin() {
|
||||||
|
return gpioPin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGpioPin(int _gpioPin) {
|
||||||
|
gpioPin = _gpioPin;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isPrimary() {
|
public boolean isPrimary() {
|
||||||
return primary;
|
return primary;
|
||||||
}
|
}
|
||||||
@@ -81,11 +107,7 @@ public class Switch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isMultilevel() {
|
public boolean isMultilevel() {
|
||||||
return multilevel;
|
return type == SwitchType.DIMMER;
|
||||||
}
|
|
||||||
|
|
||||||
public void setMultilevel(boolean _multilevel) {
|
|
||||||
multilevel = _multilevel;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isHold() {
|
public boolean isHold() {
|
||||||
@@ -96,28 +118,44 @@ public class Switch {
|
|||||||
hold = _hold;
|
hold = _hold;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getThermostatSource() {
|
public String getThermometerUrl() {
|
||||||
return thermostatSource;
|
return thermometerUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setThermostatSource(String _thermostatSource) {
|
public void setThermometerUrl(String _thermometerUrl) {
|
||||||
thermostatSource = _thermostatSource;
|
thermometerUrl = _thermometerUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getControllerUrl() {
|
||||||
|
return controllerUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setControllerUrl(String _controllerUrl) {
|
||||||
|
controllerUrl = _controllerUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isThermostat() {
|
public boolean isThermostat() {
|
||||||
return NullUtils.isNotEmpty(thermostatSource) && (nodeId < 100);
|
return isSpaceHeaterThermostat() || isZWaveThermostat();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isThermometer() {
|
public boolean isSpaceHeaterThermostat() {
|
||||||
return isUrlThermostat() && (nodeId > 99);
|
return type == SwitchType.SPACE_HEATER_THERMOSTAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isUrlThermostat() {
|
public boolean isThermometerUrlValid() {
|
||||||
return NullUtils.makeNotNull(thermostatSource).startsWith("http");
|
return NullUtils.makeNotNull(thermometerUrl).startsWith("http");
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isZWaveThermostat() {
|
public boolean isZWaveThermostat() {
|
||||||
return NullUtils.isEqual(thermostatSource, "ZWAVE");
|
return type == SwitchType.THERMOSTAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRelay() {
|
||||||
|
return type == SwitchType.RELAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isControlledBy(String _controllerUrl) {
|
||||||
|
return NullUtils.isEqual(_controllerUrl, controllerUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ThermostatMode getThermostatMode() {
|
public ThermostatMode getThermostatMode() {
|
||||||
@@ -136,6 +174,14 @@ public class Switch {
|
|||||||
lowLevel = _lowLevel;
|
lowLevel = _lowLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isHidden() {
|
||||||
|
return hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHidden(boolean _hidden) {
|
||||||
|
hidden = _hidden;
|
||||||
|
}
|
||||||
|
|
||||||
public List<SwitchSchedule> getSchedule() {
|
public List<SwitchSchedule> getSchedule() {
|
||||||
return schedule;
|
return schedule;
|
||||||
}
|
}
|
||||||
@@ -143,4 +189,40 @@ public class Switch {
|
|||||||
public void setSchedule(List<SwitchSchedule> _schedule) {
|
public void setSchedule(List<SwitchSchedule> _schedule) {
|
||||||
schedule = _schedule;
|
schedule = _schedule;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object _o) {
|
||||||
|
if (this == _o) return true;
|
||||||
|
if (_o == null || getClass() != _o.getClass()) return false;
|
||||||
|
Switch aSwitch = (Switch) _o;
|
||||||
|
return nodeId == aSwitch.nodeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(nodeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isModified(Switch _switch) {
|
||||||
|
return (_switch == null) || (level != _switch.getLevel()) || (hold != _switch.isHold()) || (thermostatMode != _switch.getThermostatMode());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Switch duplicate() {
|
||||||
|
Switch s = new Switch();
|
||||||
|
s.setType(getType());
|
||||||
|
s.setRoom(getRoom());
|
||||||
|
s.setName(getName());
|
||||||
|
s.setNodeId(getNodeId());
|
||||||
|
s.setLevel(getLevel());
|
||||||
|
s.setGpioPin(getGpioPin());
|
||||||
|
s.setPrimary(isPrimary());
|
||||||
|
s.setHold(isHold());
|
||||||
|
s.setHidden(isHidden());
|
||||||
|
s.setThermometerUrl(getThermometerUrl());
|
||||||
|
s.setControllerUrl(getControllerUrl());
|
||||||
|
s.setThermostatMode(getThermostatMode());
|
||||||
|
s.setLowLevel(getLowLevel());
|
||||||
|
s.setSchedule(CollectionUtils.transform(getSchedule(), SwitchSchedule::duplicate));
|
||||||
|
return s;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+104
-28
@@ -7,20 +7,24 @@ import com.lanternsoftware.util.dao.annotations.DBSerializable;
|
|||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.GregorianCalendar;
|
import java.util.GregorianCalendar;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
@DBSerializable
|
@DBSerializable
|
||||||
public class SwitchSchedule {
|
public class SwitchSchedule {
|
||||||
private int dayOfWeek;
|
private int dayOfWeek;
|
||||||
private int timeOfDay;
|
private int timeOfDay;
|
||||||
private int minutesPerHour;
|
private int timeOfDayEnd;
|
||||||
|
private int onDuration;
|
||||||
|
private int offDuration;
|
||||||
private int level;
|
private int level;
|
||||||
|
|
||||||
public SwitchSchedule() {
|
public SwitchSchedule() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public SwitchSchedule(int _minutesPerHour) {
|
public SwitchSchedule(int _onDuration, int _offDuration) {
|
||||||
minutesPerHour = _minutesPerHour;
|
onDuration = _onDuration;
|
||||||
|
offDuration = _offDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SwitchSchedule(int _dayOfWeek, int _timeOfDay, int _level) {
|
public SwitchSchedule(int _dayOfWeek, int _timeOfDay, int _level) {
|
||||||
@@ -64,12 +68,34 @@ public class SwitchSchedule {
|
|||||||
timeOfDay = (_hour * 3600) + (_minute * 60) + _second;
|
timeOfDay = (_hour * 3600) + (_minute * 60) + _second;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMinutesPerHour() {
|
public int getTimeOfDayEnd() {
|
||||||
return minutesPerHour;
|
return timeOfDayEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMinutesPerHour(int _minutesPerHour) {
|
public void setTimeOfDayEnd(int _timeOfDayEnd) {
|
||||||
minutesPerHour = _minutesPerHour;
|
timeOfDayEnd = _timeOfDayEnd;
|
||||||
|
}
|
||||||
|
public void setTimeOfDayEnd(int _hour, int _minute) {
|
||||||
|
timeOfDayEnd = (_hour * 3600) + (_minute * 60);
|
||||||
|
}
|
||||||
|
public void setTimeOfDayEnd(int _hour, int _minute, int _second) {
|
||||||
|
timeOfDayEnd = (_hour * 3600) + (_minute * 60) + _second;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getOnDuration() {
|
||||||
|
return onDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnDuration(int _onDuration) {
|
||||||
|
onDuration = _onDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getOffDuration() {
|
||||||
|
return offDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOffDuration(int _offDuration) {
|
||||||
|
offDuration = _offDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getLevel() {
|
public int getLevel() {
|
||||||
@@ -81,38 +107,88 @@ public class SwitchSchedule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int hour() {
|
public int hour() {
|
||||||
return timeOfDay/3600;
|
return hour(timeOfDay);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int minute() {
|
public int minute() {
|
||||||
return (timeOfDay/60)%60;
|
return minute(timeOfDay);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int second() {
|
public int second() {
|
||||||
return timeOfDay%60;
|
return second(timeOfDay);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isOn() {
|
public int hour(int _timeOfDay) {
|
||||||
return GregorianCalendar.getInstance().get(Calendar.MINUTE) < minutesPerHour;
|
return _timeOfDay/3600;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int minute(int _timeOfDay) {
|
||||||
|
return (_timeOfDay/60)%60;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int second(int _timeOfDay) {
|
||||||
|
return _timeOfDay%60;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date startToday(TimeZone _tz) {
|
||||||
|
return today(timeOfDay, _tz);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date endToday(TimeZone _tz) {
|
||||||
|
return today(timeOfDayEnd, _tz);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date today(int _timeOfDay, TimeZone _tz) {
|
||||||
|
Date now = new Date();
|
||||||
|
Calendar cal = DateUtils.toCalendar(now, _tz);
|
||||||
|
if (dayOfWeek > 0)
|
||||||
|
cal.set(Calendar.DAY_OF_WEEK, dayOfWeek);
|
||||||
|
cal.set(Calendar.HOUR_OF_DAY, hour(_timeOfDay));
|
||||||
|
cal.set(Calendar.MINUTE, minute(_timeOfDay));
|
||||||
|
cal.set(Calendar.SECOND, second(_timeOfDay));
|
||||||
|
cal.set(Calendar.MILLISECOND, 0);
|
||||||
|
return cal.getTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
public SwitchTransition getNextTransition(Switch _switch, TimeZone _tz) {
|
public SwitchTransition getNextTransition(Switch _switch, TimeZone _tz) {
|
||||||
if (minutesPerHour > 0) {
|
Date startToday = startToday(_tz);
|
||||||
Date dt = DateUtils.getStartOfHour(_tz);
|
|
||||||
Date transition = DateUtils.addMinutes(dt, minutesPerHour);
|
|
||||||
if (new Date().before(transition))
|
|
||||||
return new SwitchTransition(_switch, transition, 0);
|
|
||||||
return new SwitchTransition(_switch, DateUtils.getEndOfHour(_tz), level == 0?255:level);
|
|
||||||
}
|
|
||||||
Date now = new Date();
|
Date now = new Date();
|
||||||
Calendar cal = DateUtils.toCalendar(now, _tz);
|
if (onDuration > 0) {
|
||||||
cal.set(Calendar.DAY_OF_WEEK, dayOfWeek);
|
if ((timeOfDay > 0) && now.before(startToday))
|
||||||
cal.set(Calendar.HOUR_OF_DAY, hour());
|
now = startToday;
|
||||||
cal.set(Calendar.MINUTE, minute());
|
if (timeOfDayEnd > 0) {
|
||||||
cal.set(Calendar.SECOND, second());
|
if (now.after(endToday(_tz)))
|
||||||
cal.set(Calendar.MILLISECOND, 0);
|
now = DateUtils.addDays(startToday, (dayOfWeek > 0)?7:1, _tz);
|
||||||
if (cal.getTimeInMillis() <= now.getTime())
|
}
|
||||||
cal.add(Calendar.DAY_OF_MONTH, 7);
|
long progress = now.getTime()%((onDuration+offDuration)*1000L);
|
||||||
return new SwitchTransition(_switch, cal.getTime(), level);
|
if (progress < onDuration*1000L)
|
||||||
|
return new SwitchTransition(_switch, new Date(now.getTime() + (onDuration*1000L)-progress), 0);
|
||||||
|
return new SwitchTransition(_switch, new Date(now.getTime()+((onDuration+offDuration)*1000L)-progress), level == 0 ? 255 : level);
|
||||||
|
}
|
||||||
|
return new SwitchTransition(_switch, startToday.after(now)?startToday:DateUtils.addDays(startToday, (dayOfWeek > 0)?7:1, _tz), level);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object _o) {
|
||||||
|
if (this == _o) return true;
|
||||||
|
if (_o == null || getClass() != _o.getClass()) return false;
|
||||||
|
SwitchSchedule that = (SwitchSchedule) _o;
|
||||||
|
return dayOfWeek == that.dayOfWeek && timeOfDay == that.timeOfDay && timeOfDayEnd == that.timeOfDayEnd && onDuration == that.onDuration && offDuration == that.offDuration && level == that.level;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(dayOfWeek, timeOfDay, timeOfDayEnd, onDuration, offDuration, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SwitchSchedule duplicate() {
|
||||||
|
SwitchSchedule s = new SwitchSchedule();
|
||||||
|
s.setDayOfWeek(getDayOfWeek());
|
||||||
|
s.setTimeOfDay(getTimeOfDay());
|
||||||
|
s.setTimeOfDayEnd(getTimeOfDayEnd());
|
||||||
|
s.setOnDuration(getOnDuration());
|
||||||
|
s.setOffDuration(getOffDuration());
|
||||||
|
s.setLevel(getLevel());
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
package com.lanternsoftware.datamodel.zwave;
|
||||||
|
|
||||||
|
public enum SwitchType {
|
||||||
|
BINARY,
|
||||||
|
DIMMER,
|
||||||
|
THERMOSTAT,
|
||||||
|
SPACE_HEATER_THERMOSTAT,
|
||||||
|
THERMOMETER,
|
||||||
|
RELAY,
|
||||||
|
SECURITY
|
||||||
|
}
|
||||||
+42
-2
@@ -1,5 +1,7 @@
|
|||||||
package com.lanternsoftware.datamodel.zwave;
|
package com.lanternsoftware.datamodel.zwave;
|
||||||
|
|
||||||
|
import com.lanternsoftware.util.CollectionUtils;
|
||||||
|
import com.lanternsoftware.util.NullUtils;
|
||||||
import com.lanternsoftware.util.dao.annotations.DBSerializable;
|
import com.lanternsoftware.util.dao.annotations.DBSerializable;
|
||||||
import com.lanternsoftware.util.dao.annotations.PrimaryKey;
|
import com.lanternsoftware.util.dao.annotations.PrimaryKey;
|
||||||
|
|
||||||
@@ -7,8 +9,10 @@ import java.util.List;
|
|||||||
|
|
||||||
@DBSerializable(autogen = false)
|
@DBSerializable(autogen = false)
|
||||||
public class ZWaveConfig {
|
public class ZWaveConfig {
|
||||||
@PrimaryKey
|
@PrimaryKey private int accountId;
|
||||||
private int accountId;
|
private String commPort;
|
||||||
|
private String url;
|
||||||
|
private String masterUrl;
|
||||||
private List<Switch> switches;
|
private List<Switch> switches;
|
||||||
|
|
||||||
public int getAccountId() {
|
public int getAccountId() {
|
||||||
@@ -19,6 +23,30 @@ public class ZWaveConfig {
|
|||||||
accountId = _accountId;
|
accountId = _accountId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getCommPort() {
|
||||||
|
return commPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCommPort(String _commPort) {
|
||||||
|
commPort = _commPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUrl(String _url) {
|
||||||
|
url = _url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMasterUrl() {
|
||||||
|
return masterUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMasterUrl(String _masterUrl) {
|
||||||
|
masterUrl = _masterUrl;
|
||||||
|
}
|
||||||
|
|
||||||
public List<Switch> getSwitches() {
|
public List<Switch> getSwitches() {
|
||||||
return switches;
|
return switches;
|
||||||
}
|
}
|
||||||
@@ -26,4 +54,16 @@ public class ZWaveConfig {
|
|||||||
public void setSwitches(List<Switch> _switches) {
|
public void setSwitches(List<Switch> _switches) {
|
||||||
switches = _switches;
|
switches = _switches;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isMaster() {
|
||||||
|
return NullUtils.isEqual(url, masterUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Switch> getSwitchesForThisController() {
|
||||||
|
return CollectionUtils.filter(switches, this::isMySwitch);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMySwitch(Switch _sw) {
|
||||||
|
return (isMaster() && NullUtils.isEmpty(_sw.getControllerUrl())) || _sw.isControlledBy(getUrl());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-3
@@ -5,7 +5,6 @@ import com.lanternsoftware.util.dao.AbstractDaoSerializer;
|
|||||||
import com.lanternsoftware.util.dao.DaoEntity;
|
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.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -28,7 +27,9 @@ public class SwitchScheduleSerializer extends AbstractDaoSerializer<SwitchSchedu
|
|||||||
DaoEntity d = new DaoEntity();
|
DaoEntity d = new DaoEntity();
|
||||||
d.put("day_of_week", _o.getDayOfWeek());
|
d.put("day_of_week", _o.getDayOfWeek());
|
||||||
d.put("time_of_day", _o.getTimeOfDay());
|
d.put("time_of_day", _o.getTimeOfDay());
|
||||||
d.put("minutes_per_hour", _o.getMinutesPerHour());
|
d.put("time_of_day_end", _o.getTimeOfDayEnd());
|
||||||
|
d.put("on_duration", _o.getOnDuration());
|
||||||
|
d.put("off_duration", _o.getOffDuration());
|
||||||
d.put("level", _o.getLevel());
|
d.put("level", _o.getLevel());
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
@@ -39,7 +40,9 @@ public class SwitchScheduleSerializer extends AbstractDaoSerializer<SwitchSchedu
|
|||||||
SwitchSchedule o = new SwitchSchedule();
|
SwitchSchedule o = new SwitchSchedule();
|
||||||
o.setDayOfWeek(DaoSerializer.getInteger(_d, "day_of_week"));
|
o.setDayOfWeek(DaoSerializer.getInteger(_d, "day_of_week"));
|
||||||
o.setTimeOfDay(DaoSerializer.getInteger(_d, "time_of_day"));
|
o.setTimeOfDay(DaoSerializer.getInteger(_d, "time_of_day"));
|
||||||
o.setMinutesPerHour(DaoSerializer.getInteger(_d, "minutes_per_hour"));
|
o.setTimeOfDayEnd(DaoSerializer.getInteger(_d, "time_of_day_end"));
|
||||||
|
o.setOnDuration(DaoSerializer.getInteger(_d, "on_duration"));
|
||||||
|
o.setOffDuration(DaoSerializer.getInteger(_d, "off_duration"));
|
||||||
o.setLevel(DaoSerializer.getInteger(_d, "level"));
|
o.setLevel(DaoSerializer.getInteger(_d, "level"));
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-5
@@ -2,12 +2,12 @@ package com.lanternsoftware.datamodel.zwave.dao;
|
|||||||
|
|
||||||
import com.lanternsoftware.datamodel.zwave.Switch;
|
import com.lanternsoftware.datamodel.zwave.Switch;
|
||||||
import com.lanternsoftware.datamodel.zwave.SwitchSchedule;
|
import com.lanternsoftware.datamodel.zwave.SwitchSchedule;
|
||||||
|
import com.lanternsoftware.datamodel.zwave.SwitchType;
|
||||||
import com.lanternsoftware.datamodel.zwave.ThermostatMode;
|
import com.lanternsoftware.datamodel.zwave.ThermostatMode;
|
||||||
import com.lanternsoftware.util.dao.AbstractDaoSerializer;
|
import com.lanternsoftware.util.dao.AbstractDaoSerializer;
|
||||||
import com.lanternsoftware.util.dao.DaoEntity;
|
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.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -28,16 +28,19 @@ public class SwitchSerializer extends AbstractDaoSerializer<Switch>
|
|||||||
public DaoEntity toDaoEntity(Switch _o)
|
public DaoEntity toDaoEntity(Switch _o)
|
||||||
{
|
{
|
||||||
DaoEntity d = new DaoEntity();
|
DaoEntity d = new DaoEntity();
|
||||||
|
d.put("type", DaoSerializer.toEnumName(_o.getType()));
|
||||||
d.put("room", _o.getRoom());
|
d.put("room", _o.getRoom());
|
||||||
d.put("name", _o.getName());
|
d.put("name", _o.getName());
|
||||||
d.put("node_id", _o.getNodeId());
|
d.put("node_id", _o.getNodeId());
|
||||||
d.put("level", _o.getLevel());
|
d.put("level", _o.getLevel());
|
||||||
|
d.put("gpio_pin", _o.getGpioPin());
|
||||||
d.put("primary", _o.isPrimary());
|
d.put("primary", _o.isPrimary());
|
||||||
d.put("multilevel", _o.isMultilevel());
|
|
||||||
d.put("hold", _o.isHold());
|
d.put("hold", _o.isHold());
|
||||||
d.put("thermostat_source", _o.getThermostatSource());
|
d.put("thermometer_url", _o.getThermometerUrl());
|
||||||
|
d.put("controller_url", _o.getControllerUrl());
|
||||||
d.put("thermostat_mode", DaoSerializer.toEnumName(_o.getThermostatMode()));
|
d.put("thermostat_mode", DaoSerializer.toEnumName(_o.getThermostatMode()));
|
||||||
d.put("low_level", _o.getLowLevel());
|
d.put("low_level", _o.getLowLevel());
|
||||||
|
d.put("hidden", _o.isHidden());
|
||||||
d.put("schedule", DaoSerializer.toDaoEntities(_o.getSchedule(), DaoProxyType.MONGO));
|
d.put("schedule", DaoSerializer.toDaoEntities(_o.getSchedule(), DaoProxyType.MONGO));
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
@@ -46,16 +49,19 @@ public class SwitchSerializer extends AbstractDaoSerializer<Switch>
|
|||||||
public Switch fromDaoEntity(DaoEntity _d)
|
public Switch fromDaoEntity(DaoEntity _d)
|
||||||
{
|
{
|
||||||
Switch o = new Switch();
|
Switch o = new Switch();
|
||||||
|
o.setType(DaoSerializer.getEnum(_d, "type", SwitchType.class));
|
||||||
o.setRoom(DaoSerializer.getString(_d, "room"));
|
o.setRoom(DaoSerializer.getString(_d, "room"));
|
||||||
o.setName(DaoSerializer.getString(_d, "name"));
|
o.setName(DaoSerializer.getString(_d, "name"));
|
||||||
o.setNodeId(DaoSerializer.getInteger(_d, "node_id"));
|
o.setNodeId(DaoSerializer.getInteger(_d, "node_id"));
|
||||||
o.setLevel(DaoSerializer.getInteger(_d, "level"));
|
o.setLevel(DaoSerializer.getInteger(_d, "level"));
|
||||||
|
o.setGpioPin(DaoSerializer.getInteger(_d, "gpio_pin"));
|
||||||
o.setPrimary(DaoSerializer.getBoolean(_d, "primary"));
|
o.setPrimary(DaoSerializer.getBoolean(_d, "primary"));
|
||||||
o.setMultilevel(DaoSerializer.getBoolean(_d, "multilevel"));
|
|
||||||
o.setHold(DaoSerializer.getBoolean(_d, "hold"));
|
o.setHold(DaoSerializer.getBoolean(_d, "hold"));
|
||||||
o.setThermostatSource(DaoSerializer.getString(_d, "thermostat_source"));
|
o.setThermometerUrl(DaoSerializer.getString(_d, "thermometer_url"));
|
||||||
|
o.setControllerUrl(DaoSerializer.getString(_d, "controller_url"));
|
||||||
o.setThermostatMode(DaoSerializer.getEnum(_d, "thermostat_mode", ThermostatMode.class));
|
o.setThermostatMode(DaoSerializer.getEnum(_d, "thermostat_mode", ThermostatMode.class));
|
||||||
o.setLowLevel(DaoSerializer.getInteger(_d, "low_level"));
|
o.setLowLevel(DaoSerializer.getInteger(_d, "low_level"));
|
||||||
|
o.setHidden(DaoSerializer.getBoolean(_d, "hidden"));
|
||||||
o.setSchedule(DaoSerializer.getList(_d, "schedule", SwitchSchedule.class));
|
o.setSchedule(DaoSerializer.getList(_d, "schedule", SwitchSchedule.class));
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|||||||
+6
@@ -28,6 +28,9 @@ public class ZWaveConfigSerializer extends AbstractDaoSerializer<ZWaveConfig>
|
|||||||
{
|
{
|
||||||
DaoEntity d = new DaoEntity();
|
DaoEntity d = new DaoEntity();
|
||||||
d.put("_id", String.valueOf(_o.getAccountId()));
|
d.put("_id", String.valueOf(_o.getAccountId()));
|
||||||
|
d.put("comm_port", _o.getCommPort());
|
||||||
|
d.put("url", _o.getUrl());
|
||||||
|
d.put("master_url", _o.getMasterUrl());
|
||||||
d.put("switches", DaoSerializer.toDaoEntities(_o.getSwitches(), DaoProxyType.MONGO));
|
d.put("switches", DaoSerializer.toDaoEntities(_o.getSwitches(), DaoProxyType.MONGO));
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
@@ -37,6 +40,9 @@ public class ZWaveConfigSerializer extends AbstractDaoSerializer<ZWaveConfig>
|
|||||||
{
|
{
|
||||||
ZWaveConfig o = new ZWaveConfig();
|
ZWaveConfig o = new ZWaveConfig();
|
||||||
o.setAccountId(DaoSerializer.getInteger(_d, "_id"));
|
o.setAccountId(DaoSerializer.getInteger(_d, "_id"));
|
||||||
|
o.setCommPort(DaoSerializer.getString(_d, "comm_port"));
|
||||||
|
o.setUrl(DaoSerializer.getString(_d, "url"));
|
||||||
|
o.setMasterUrl(DaoSerializer.getString(_d, "master_url"));
|
||||||
o.setSwitches(DaoSerializer.getList(_d, "switches", Switch.class));
|
o.setSwitches(DaoSerializer.getList(_d, "switches", Switch.class));
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,9 +20,14 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.lanternsoftware.currentmonitor</groupId>
|
<groupId>com.lanternsoftware.currentmonitor</groupId>
|
||||||
<artifactId>lantern-dataaccess-currentmonitor</artifactId>
|
<artifactId>lantern-datamodel-currentmonitor</artifactId>
|
||||||
<version>1.0.0</version>
|
<version>1.0.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.pi4j</groupId>
|
||||||
|
<artifactId>pi4j-gpio-extension</artifactId>
|
||||||
|
<version>1.3</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.lanternsoftware.zwave</groupId>
|
<groupId>com.lanternsoftware.zwave</groupId>
|
||||||
<artifactId>lantern-zwave</artifactId>
|
<artifactId>lantern-zwave</artifactId>
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package com.lanternsoftware.zwave;
|
||||||
|
|
||||||
|
import com.lanternsoftware.datamodel.zwave.Switch;
|
||||||
|
import com.lanternsoftware.datamodel.zwave.SwitchType;
|
||||||
|
import com.lanternsoftware.zwave.security.SecurityController;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class TestSecurity {
|
||||||
|
protected static final Logger LOG = LoggerFactory.getLogger(TestSecurity.class);
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SecurityController c = new SecurityController();
|
||||||
|
Switch sw = new Switch("Garage", "Door 1", 1000, true, false, null, 0);
|
||||||
|
sw.setGpioPin(7);
|
||||||
|
sw.setType(SwitchType.SECURITY);
|
||||||
|
c.listen(sw, (nodeId, _open) -> LOG.info("Door is " + (_open ? "OPEN" : "CLOSED")));
|
||||||
|
}
|
||||||
|
}
|
||||||
-8
@@ -1,19 +1,13 @@
|
|||||||
package com.lanternsoftware.zwave.context;
|
package com.lanternsoftware.zwave.context;
|
||||||
|
|
||||||
import com.lanternsoftware.dataaccess.currentmonitor.MongoCurrentMonitorDao;
|
|
||||||
import com.lanternsoftware.util.LanternFiles;
|
|
||||||
import com.lanternsoftware.util.dao.mongo.MongoConfig;
|
|
||||||
|
|
||||||
import javax.servlet.ServletContextEvent;
|
import javax.servlet.ServletContextEvent;
|
||||||
import javax.servlet.ServletContextListener;
|
import javax.servlet.ServletContextListener;
|
||||||
|
|
||||||
public class Globals implements ServletContextListener {
|
public class Globals implements ServletContextListener {
|
||||||
public static ZWaveApp app;
|
public static ZWaveApp app;
|
||||||
public static MongoCurrentMonitorDao cmDao;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void contextInitialized(ServletContextEvent sce) {
|
public void contextInitialized(ServletContextEvent sce) {
|
||||||
cmDao = new MongoCurrentMonitorDao(MongoConfig.fromDisk(LanternFiles.OPS_PATH + "mongo.cfg"));
|
|
||||||
app = new ZWaveApp();
|
app = new ZWaveApp();
|
||||||
app.start();
|
app.start();
|
||||||
}
|
}
|
||||||
@@ -24,7 +18,5 @@ public class Globals implements ServletContextListener {
|
|||||||
app.stop();
|
app.stop();
|
||||||
app = null;
|
app = null;
|
||||||
}
|
}
|
||||||
if (cmDao != null)
|
|
||||||
cmDao.shutdown();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+152
-48
@@ -1,5 +1,6 @@
|
|||||||
package com.lanternsoftware.zwave.context;
|
package com.lanternsoftware.zwave.context;
|
||||||
|
|
||||||
|
import com.lanternsoftware.datamodel.currentmonitor.AuthCode;
|
||||||
import com.lanternsoftware.datamodel.zwave.Switch;
|
import com.lanternsoftware.datamodel.zwave.Switch;
|
||||||
import com.lanternsoftware.datamodel.zwave.SwitchSchedule;
|
import com.lanternsoftware.datamodel.zwave.SwitchSchedule;
|
||||||
import com.lanternsoftware.datamodel.zwave.SwitchTransition;
|
import com.lanternsoftware.datamodel.zwave.SwitchTransition;
|
||||||
@@ -9,7 +10,9 @@ import com.lanternsoftware.util.CollectionUtils;
|
|||||||
import com.lanternsoftware.util.DateUtils;
|
import com.lanternsoftware.util.DateUtils;
|
||||||
import com.lanternsoftware.util.LanternFiles;
|
import com.lanternsoftware.util.LanternFiles;
|
||||||
import com.lanternsoftware.util.NullUtils;
|
import com.lanternsoftware.util.NullUtils;
|
||||||
|
import com.lanternsoftware.util.ResourceLoader;
|
||||||
import com.lanternsoftware.util.concurrency.ConcurrencyUtils;
|
import com.lanternsoftware.util.concurrency.ConcurrencyUtils;
|
||||||
|
import com.lanternsoftware.util.cryptography.AESTool;
|
||||||
import com.lanternsoftware.util.dao.DaoSerializer;
|
import com.lanternsoftware.util.dao.DaoSerializer;
|
||||||
import com.lanternsoftware.util.dao.mongo.MongoConfig;
|
import com.lanternsoftware.util.dao.mongo.MongoConfig;
|
||||||
import com.lanternsoftware.util.http.HttpPool;
|
import com.lanternsoftware.util.http.HttpPool;
|
||||||
@@ -19,6 +22,7 @@ import com.lanternsoftware.zwave.message.IMessageSubscriber;
|
|||||||
import com.lanternsoftware.zwave.message.MessageEngine;
|
import com.lanternsoftware.zwave.message.MessageEngine;
|
||||||
import com.lanternsoftware.zwave.message.impl.BinarySwitchReportRequest;
|
import com.lanternsoftware.zwave.message.impl.BinarySwitchReportRequest;
|
||||||
import com.lanternsoftware.zwave.message.impl.BinarySwitchSetRequest;
|
import com.lanternsoftware.zwave.message.impl.BinarySwitchSetRequest;
|
||||||
|
import com.lanternsoftware.zwave.message.impl.CRC16EncapRequest;
|
||||||
import com.lanternsoftware.zwave.message.impl.MultilevelSensorGetRequest;
|
import com.lanternsoftware.zwave.message.impl.MultilevelSensorGetRequest;
|
||||||
import com.lanternsoftware.zwave.message.impl.MultilevelSensorReportRequest;
|
import com.lanternsoftware.zwave.message.impl.MultilevelSensorReportRequest;
|
||||||
import com.lanternsoftware.zwave.message.impl.MultilevelSwitchReportRequest;
|
import com.lanternsoftware.zwave.message.impl.MultilevelSwitchReportRequest;
|
||||||
@@ -27,7 +31,10 @@ import com.lanternsoftware.zwave.message.impl.ThermostatModeSetRequest;
|
|||||||
import com.lanternsoftware.zwave.message.impl.ThermostatSetPointReportRequest;
|
import com.lanternsoftware.zwave.message.impl.ThermostatSetPointReportRequest;
|
||||||
import com.lanternsoftware.zwave.message.impl.ThermostatSetPointSetRequest;
|
import com.lanternsoftware.zwave.message.impl.ThermostatSetPointSetRequest;
|
||||||
import com.lanternsoftware.zwave.message.thermostat.ThermostatSetPointIndex;
|
import com.lanternsoftware.zwave.message.thermostat.ThermostatSetPointIndex;
|
||||||
|
import com.lanternsoftware.zwave.relay.RelayController;
|
||||||
import org.apache.http.client.methods.HttpGet;
|
import org.apache.http.client.methods.HttpGet;
|
||||||
|
import org.apache.http.client.methods.HttpPost;
|
||||||
|
import org.apache.http.entity.ByteArrayEntity;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -35,31 +42,57 @@ import java.util.Comparator;
|
|||||||
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.Set;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
|
|
||||||
public class ZWaveApp {
|
public class ZWaveApp {
|
||||||
|
public static final AESTool aes = new AESTool(ResourceLoader.loadFile(LanternFiles.OPS_PATH + "authKey.dat"));
|
||||||
|
public static String authCode = aes.encryptToBase64(DaoSerializer.toZipBson(new AuthCode(100, null)));
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(ZWaveApp.class);
|
private static final Logger logger = LoggerFactory.getLogger(ZWaveApp.class);
|
||||||
|
|
||||||
private MongoZWaveDao dao;
|
private MongoZWaveDao dao;
|
||||||
private ZWaveConfig config;
|
private ZWaveConfig config;
|
||||||
private Controller controller;
|
private Controller controller;
|
||||||
|
private RelayController relayController;
|
||||||
|
private final Map<Integer, Switch> originalSwitches = new HashMap<>();
|
||||||
private final Map<Integer, Switch> switches = new HashMap<>();
|
private final Map<Integer, Switch> switches = new HashMap<>();
|
||||||
|
private final Map<Integer, Switch> mySwitches = new HashMap<>();
|
||||||
private final Map<Integer, List<Switch>> peers = new HashMap<>();
|
private final Map<Integer, List<Switch>> peers = new HashMap<>();
|
||||||
private Timer timer;
|
private Timer timer;
|
||||||
private HttpPool pool;
|
private HttpPool pool;
|
||||||
private SwitchScheduleTask nextScheduleTask;
|
private SwitchScheduleTask nextScheduleTask;
|
||||||
private final Map<Integer, Double> temperatures = new HashMap<>();
|
private final Map<Integer, Double> sensors = new HashMap<>();
|
||||||
private final Object ZWAVE_MUTEX = new Object();
|
private final Object ZWAVE_MUTEX = new Object();
|
||||||
|
|
||||||
public void start() {
|
public void start() {
|
||||||
try {
|
try {
|
||||||
|
pool = new HttpPool(100, 20, 5000, 5000, 5000);
|
||||||
|
config = DaoSerializer.parse(ResourceLoader.loadFile(LanternFiles.OPS_PATH + "config.json"), ZWaveConfig.class);
|
||||||
|
if (config == null) {
|
||||||
dao = new MongoZWaveDao(MongoConfig.fromDisk(LanternFiles.OPS_PATH + "mongo.cfg"));
|
dao = new MongoZWaveDao(MongoConfig.fromDisk(LanternFiles.OPS_PATH + "mongo.cfg"));
|
||||||
|
config = dao.getConfig(1);
|
||||||
|
}
|
||||||
|
if (NullUtils.isNotEmpty(config.getCommPort())) {
|
||||||
controller = new Controller();
|
controller = new Controller();
|
||||||
controller.start("COM4");
|
controller.start(config.getCommPort());
|
||||||
|
}
|
||||||
|
if (!config.isMaster()) {
|
||||||
|
HttpGet get = new HttpGet(config.getMasterUrl() + "/config");
|
||||||
|
get.setHeader("auth_code", authCode);
|
||||||
|
ZWaveConfig switchConfig = DaoSerializer.parse(pool.executeToString(get), ZWaveConfig.class);
|
||||||
|
if (switchConfig != null) {
|
||||||
|
config.setSwitches(switchConfig.getSwitches());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
logger.error("Failed to retrieve switch config from master controller");
|
||||||
|
stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
timer = new Timer("ZWaveApp Timer");
|
timer = new Timer("ZWaveApp Timer");
|
||||||
pool = new HttpPool(10, 10, 30000, 10000, 10000);
|
|
||||||
|
|
||||||
//// for (int node = 3; node < 7; node++) {
|
//// for (int node = 3; node < 7; node++) {
|
||||||
// session.doAction(new ConfigurationSetAction(node, (byte) 7, new byte[]{99}));
|
// session.doAction(new ConfigurationSetAction(node, (byte) 7, new byte[]{99}));
|
||||||
@@ -78,20 +111,26 @@ public class ZWaveApp {
|
|||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
t.printStackTrace();
|
t.printStackTrace();
|
||||||
}
|
}
|
||||||
config = dao.getConfig(1);
|
|
||||||
Map<String, List<Switch>> groups = new HashMap<>();
|
Map<String, List<Switch>> groups = new HashMap<>();
|
||||||
for (Switch sw : CollectionUtils.makeNotNull(config.getSwitches())) {
|
for (Switch sw : config.getSwitches()) {
|
||||||
switches.put(sw.getNodeId(), sw);
|
switches.put(sw.getNodeId(), sw);
|
||||||
|
originalSwitches.put(sw.getNodeId(), sw.duplicate());
|
||||||
|
if (config.isMySwitch(sw))
|
||||||
|
mySwitches.put(sw.getNodeId(), sw);
|
||||||
CollectionUtils.addToMultiMap(sw.getRoom() + ":" + sw.getName(), sw, groups);
|
CollectionUtils.addToMultiMap(sw.getRoom() + ":" + sw.getName(), sw, groups);
|
||||||
}
|
}
|
||||||
if (CollectionUtils.filterOne(config.getSwitches(), Switch::isUrlThermostat) != null) {
|
if (CollectionUtils.anyQualify(mySwitches.values(), Switch::isThermometerUrlValid)) {
|
||||||
timer.scheduleAtFixedRate(new ThermostatTask(), 0, 30000);
|
timer.scheduleAtFixedRate(new ThermostatTask(), 0, 30000);
|
||||||
}
|
}
|
||||||
|
if (CollectionUtils.anyQualify(mySwitches.values(), Switch::isRelay)) {
|
||||||
|
relayController = new RelayController();
|
||||||
|
}
|
||||||
for (List<Switch> group : groups.values()) {
|
for (List<Switch> group : groups.values()) {
|
||||||
for (Switch sw : group) {
|
for (Switch sw : group) {
|
||||||
peers.put(sw.getNodeId(), CollectionUtils.filter(group, _sw -> _sw.getNodeId() != sw.getNodeId()));
|
peers.put(sw.getNodeId(), CollectionUtils.filter(group, _sw -> _sw.getNodeId() != sw.getNodeId()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
System.out.println("My Switches:\n" + DaoSerializer.toJson(DaoSerializer.toDaoEntities(mySwitches.values())));
|
||||||
scheduleNextTransition();
|
scheduleNextTransition();
|
||||||
|
|
||||||
MessageEngine.subscribe(new IMessageSubscriber<MultilevelSensorReportRequest>() {
|
MessageEngine.subscribe(new IMessageSubscriber<MultilevelSensorReportRequest>() {
|
||||||
@@ -102,9 +141,9 @@ public class ZWaveApp {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMessage(MultilevelSensorReportRequest _message) {
|
public void onMessage(MultilevelSensorReportRequest _message) {
|
||||||
synchronized (temperatures) {
|
synchronized (sensors) {
|
||||||
temperatures.put((int) _message.getNodeId(), _message.getTemperatureCelsius());
|
sensors.put((int) _message.getNodeId(), _message.getTemperatureCelsius());
|
||||||
temperatures.notify();
|
sensors.notify();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -153,6 +192,18 @@ public class ZWaveApp {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
MessageEngine.subscribe(new IMessageSubscriber<CRC16EncapRequest>() {
|
||||||
|
@Override
|
||||||
|
public Class<CRC16EncapRequest> getHandledMessageClass() {
|
||||||
|
return CRC16EncapRequest.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMessage(CRC16EncapRequest _message) {
|
||||||
|
onSwitchLevelChange(_message.getNodeId(), _message.isOn()?0xFF:0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// controller.send(new MultilevelSensorGetRequest((byte)11));
|
// controller.send(new MultilevelSensorGetRequest((byte)11));
|
||||||
// controller.send(new ThermostatSetPointGetRequest((byte)11, ThermostatSetPointIndex.HEATING));
|
// controller.send(new ThermostatSetPointGetRequest((byte)11, ThermostatSetPointIndex.HEATING));
|
||||||
// controller.send(new ThermostatSetPointGetRequest((byte)11, ThermostatSetPointIndex.COOLING));
|
// controller.send(new ThermostatSetPointGetRequest((byte)11, ThermostatSetPointIndex.COOLING));
|
||||||
@@ -165,23 +216,24 @@ public class ZWaveApp {
|
|||||||
// controller.send(new ThermostatModeGetRequest((byte)11));
|
// controller.send(new ThermostatModeGetRequest((byte)11));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onSwitchLevelChange(int _primaryNodeId, int _primaryLevel) {
|
private void onSwitchLevelChange(int _secondaryNodeId, int _primaryLevel) {
|
||||||
synchronized (switches) {
|
synchronized (switches) {
|
||||||
Switch sw = switches.get(_primaryNodeId);
|
Switch sw = switches.get(_secondaryNodeId);
|
||||||
if (sw != null) {
|
if ((sw != null) && !sw.isPrimary()) {
|
||||||
int newLevel = sw.isMultilevel()?_primaryLevel:((_primaryLevel == 0)?0:99);
|
int newLevel = sw.isMultilevel()?_primaryLevel:((_primaryLevel == 0)?0:99);
|
||||||
sw.setLevel(newLevel);
|
sw.setLevel(newLevel);
|
||||||
for (Switch peer : CollectionUtils.makeNotNull(peers.get(_primaryNodeId))) {
|
for (Switch peer : CollectionUtils.makeNotNull(peers.get(_secondaryNodeId))) {
|
||||||
logger.info("Mirror Event from node {} to node {}", _primaryNodeId, peer.getNodeId());
|
if (peer.isPrimary()) {
|
||||||
|
logger.info("Mirror Event from node {} to node {}", _secondaryNodeId, peer.getNodeId());
|
||||||
if (peer.isMultilevel()) {
|
if (peer.isMultilevel()) {
|
||||||
peer.setLevel(newLevel);
|
peer.setLevel(newLevel);
|
||||||
controller.send(new MultilevelSwitchSetRequest((byte) peer.getNodeId(), newLevel));
|
controller.send(new MultilevelSwitchSetRequest((byte) peer.getNodeId(), newLevel));
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
peer.setLevel(newLevel > 0 ? 0xff : 0);
|
peer.setLevel(newLevel > 0 ? 0xff : 0);
|
||||||
controller.send(new BinarySwitchSetRequest((byte) peer.getNodeId(), newLevel > 0));
|
controller.send(new BinarySwitchSetRequest((byte) peer.getNodeId(), newLevel > 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
persistConfig();
|
persistConfig();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -191,7 +243,7 @@ public class ZWaveApp {
|
|||||||
TimeZone tz = TimeZone.getTimeZone("America/Chicago");
|
TimeZone tz = TimeZone.getTimeZone("America/Chicago");
|
||||||
if (nextScheduleTask != null)
|
if (nextScheduleTask != null)
|
||||||
nextScheduleTask.cancel();
|
nextScheduleTask.cancel();
|
||||||
List<SwitchTransition> nextTransitions = CollectionUtils.getAllSmallest(CollectionUtils.aggregate(switches.values(), _s->CollectionUtils.transform(_s.getSchedule(), _t->_t.getNextTransition(_s, tz))), Comparator.comparing(SwitchTransition::getTransitionTime));
|
List<SwitchTransition> nextTransitions = CollectionUtils.getAllSmallest(CollectionUtils.aggregate(mySwitches.values(), _s->CollectionUtils.transform(_s.getSchedule(), _t->_t.getNextTransition(_s, tz))), Comparator.comparing(SwitchTransition::getTransitionTime));
|
||||||
if (!CollectionUtils.isEmpty(nextTransitions)) {
|
if (!CollectionUtils.isEmpty(nextTransitions)) {
|
||||||
for (SwitchTransition tr : nextTransitions) {
|
for (SwitchTransition tr : nextTransitions) {
|
||||||
logger.info("Next transition scheduled for node {} to level {} at {}", tr.getSwitch().getNodeId(), tr.getLevel(), DateUtils.format("hh:mm:ssa", tz, tr.getTransitionTime()));
|
logger.info("Next transition scheduled for node {} to level {} at {}", tr.getSwitch().getNodeId(), tr.getLevel(), DateUtils.format("hh:mm:ssa", tz, tr.getTransitionTime()));
|
||||||
@@ -203,24 +255,31 @@ public class ZWaveApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setSwitchLevel(int _nodeId, int _level) {
|
public void setSwitchLevel(int _nodeId, int _level) {
|
||||||
|
setSwitchLevel(_nodeId, _level, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSwitchLevel(int _nodeId, int _level, boolean _updatePeers) {
|
||||||
Switch sw = switches.get(_nodeId);
|
Switch sw = switches.get(_nodeId);
|
||||||
if ((sw == null) || !sw.isPrimary())
|
if ((sw == null) || !sw.isPrimary())
|
||||||
return;
|
return;
|
||||||
sw.setLevel(_level);
|
sw.setLevel(_level);
|
||||||
if (!sw.isThermostat()) {
|
if (config.isMySwitch(sw)) {
|
||||||
setGroupSwitchLevel(sw, _level);
|
if (sw.isSpaceHeaterThermostat()) {
|
||||||
|
checkThermostat(sw);
|
||||||
} else if (sw.isZWaveThermostat()) {
|
} else if (sw.isZWaveThermostat()) {
|
||||||
controller.send(new ThermostatSetPointSetRequest((byte) sw.getNodeId(), sw.getThermostatMode() == ThermostatMode.COOL ? ThermostatSetPointIndex.COOLING : ThermostatSetPointIndex.HEATING, _level));
|
controller.send(new ThermostatSetPointSetRequest((byte) sw.getNodeId(), sw.getThermostatMode() == ThermostatMode.COOL ? ThermostatSetPointIndex.COOLING : ThermostatSetPointIndex.HEATING, _level));
|
||||||
|
} else if (sw.isRelay()) {
|
||||||
|
relayController.setRelay(sw.getGpioPin(), sw.getLevel() > 0);
|
||||||
} else {
|
} else {
|
||||||
if (timer != null)
|
setGroupSwitchLevel(sw, _level);
|
||||||
timer.schedule(new ThermostatTask(), 0);
|
|
||||||
persistConfig();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
persistConfig(_updatePeers);
|
||||||
|
}
|
||||||
|
|
||||||
public void setThermostatMode(int _nodeId, ThermostatMode _mode) {
|
public void setThermostatMode(int _nodeId, ThermostatMode _mode) {
|
||||||
Switch sw = switches.get(_nodeId);
|
Switch sw = switches.get(_nodeId);
|
||||||
if ((sw == null) || !sw.isPrimary() || !sw.isZWaveThermostat())
|
if ((sw == null) || !sw.isPrimary() || !sw.isZWaveThermostat() || !config.isMySwitch(sw))
|
||||||
return;
|
return;
|
||||||
controller.send(new ThermostatModeSetRequest((byte) sw.getNodeId(), com.lanternsoftware.zwave.message.thermostat.ThermostatMode.fromByte(_mode.data)));
|
controller.send(new ThermostatModeSetRequest((byte) sw.getNodeId(), com.lanternsoftware.zwave.message.thermostat.ThermostatMode.fromByte(_mode.data)));
|
||||||
sw.setThermostatMode(_mode);
|
sw.setThermostatMode(_mode);
|
||||||
@@ -236,6 +295,12 @@ public class ZWaveApp {
|
|||||||
scheduleNextTransition();
|
scheduleNextTransition();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updateSwitch(Switch _sw) {
|
||||||
|
switches.put(_sw.getNodeId(), _sw);
|
||||||
|
mySwitches.put(_sw.getNodeId(), _sw);
|
||||||
|
setSwitchLevel(_sw.getNodeId(), _sw.getLevel(), false);
|
||||||
|
}
|
||||||
|
|
||||||
public void setSwitchHold(int _nodeId, boolean _hold) {
|
public void setSwitchHold(int _nodeId, boolean _hold) {
|
||||||
Switch sw = switches.get(_nodeId);
|
Switch sw = switches.get(_nodeId);
|
||||||
if ((sw == null) || !sw.isPrimary())
|
if ((sw == null) || !sw.isPrimary())
|
||||||
@@ -245,8 +310,37 @@ public class ZWaveApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void persistConfig() {
|
private void persistConfig() {
|
||||||
|
persistConfig(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void persistConfig(boolean _updatePeers) {
|
||||||
|
List<Switch> modified;
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
|
modified = CollectionUtils.filter(switches.values(), _s->_s.isModified(originalSwitches.get(_s.getNodeId())));
|
||||||
|
if (!modified.isEmpty()) {
|
||||||
|
originalSwitches.clear();
|
||||||
|
for (Switch s : switches.values()) {
|
||||||
|
originalSwitches.put(s.getNodeId(), s.duplicate());
|
||||||
|
}
|
||||||
|
if (config.isMaster()) {
|
||||||
|
if (dao != null)
|
||||||
dao.putConfig(config);
|
dao.putConfig(config);
|
||||||
|
else
|
||||||
|
ResourceLoader.writeFile(LanternFiles.OPS_PATH + "config.json", DaoSerializer.toJson(config));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_updatePeers) {
|
||||||
|
Set<String> peers = CollectionUtils.transformToSet(modified, Switch::getControllerUrl);
|
||||||
|
peers.remove(config.getUrl());
|
||||||
|
for (String peer : peers) {
|
||||||
|
for (Switch sw : modified) {
|
||||||
|
HttpPost post = new HttpPost(peer + "/switch/" + sw.getNodeId());
|
||||||
|
post.setHeader("auth_code", authCode);
|
||||||
|
post.setEntity(new ByteArrayEntity(DaoSerializer.toZipBson(sw)));
|
||||||
|
pool.execute(post);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,6 +355,10 @@ public class ZWaveApp {
|
|||||||
|
|
||||||
public void stop() {
|
public void stop() {
|
||||||
controller.stop();
|
controller.stop();
|
||||||
|
if (relayController != null) {
|
||||||
|
relayController.shutdown();
|
||||||
|
relayController = null;
|
||||||
|
}
|
||||||
if (timer != null) {
|
if (timer != null) {
|
||||||
timer.cancel();
|
timer.cancel();
|
||||||
timer = null;
|
timer = null;
|
||||||
@@ -276,11 +374,12 @@ public class ZWaveApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setGroupSwitchLevel(Switch _primary, int _level) {
|
private void setGroupSwitchLevel(Switch _primary, int _level) {
|
||||||
if (_primary == null)
|
if ((_primary == null) || !config.isMySwitch(_primary))
|
||||||
return;
|
return;
|
||||||
List<Switch> nodes = CollectionUtils.asArrayList(_primary);
|
List<Switch> nodes = CollectionUtils.asArrayList(_primary);
|
||||||
nodes.addAll(CollectionUtils.makeNotNull(peers.get(_primary.getNodeId())));
|
nodes.addAll(CollectionUtils.filter(peers.get(_primary.getNodeId()), _p->!_p.isPrimary()));
|
||||||
for (Switch node : nodes) {
|
for (Switch node : nodes) {
|
||||||
|
logger.info("Setting {}, Node {} to {}", node.getName(), node.getNodeId(), _level);
|
||||||
controller.send(node.isMultilevel() ? new MultilevelSwitchSetRequest((byte) node.getNodeId(), _level) : new BinarySwitchSetRequest((byte) node.getNodeId(), _level > 0));
|
controller.send(node.isMultilevel() ? new MultilevelSwitchSetRequest((byte) node.getNodeId(), _level) : new BinarySwitchSetRequest((byte) node.getNodeId(), _level > 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -288,23 +387,27 @@ public class ZWaveApp {
|
|||||||
private class ThermostatTask extends TimerTask {
|
private class ThermostatTask extends TimerTask {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
for (Switch sw : switches.values()) {
|
for (Switch sw : mySwitches.values()) {
|
||||||
|
checkThermostat(sw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkThermostat(Switch _sw) {
|
||||||
try {
|
try {
|
||||||
if (sw.isUrlThermostat() && !sw.isThermometer()) {
|
if (_sw.isSpaceHeaterThermostat()) {
|
||||||
double tempF = getTemperatureCelsius(sw) * 1.8 + 32;
|
double tempF = getTemperatureCelsius(_sw) * 1.8 + 32;
|
||||||
if (tempF > sw.getLevel() + 0.4) {
|
if (tempF > _sw.getLevel() + 0.4) {
|
||||||
setGroupSwitchLevel(sw, 0);
|
setGroupSwitchLevel(_sw, 0);
|
||||||
logger.info("Turning {} {} off, temp is: {} set to: {}", sw.getRoom(), sw.getName(), tempF + " set to: ", sw.getLevel());
|
logger.info("Turning {} {} off, temp is: {} set to: {}", _sw.getRoom(), _sw.getName(), tempF, _sw.getLevel());
|
||||||
} else if (tempF < sw.getLevel() - 0.4) {
|
} else if (tempF < _sw.getLevel() - 0.4) {
|
||||||
setGroupSwitchLevel(sw, (byte) 0xf);
|
setGroupSwitchLevel(_sw, 255);
|
||||||
logger.info("Turning {} {} on, temp is: {} set to: {}", sw.getRoom(), sw.getName(), tempF + " set to: ", sw.getLevel());
|
logger.info("Turning {} {} on, temp is: {} set to: {}", _sw.getRoom(), _sw.getName(), tempF, _sw.getLevel());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Throwable t) {
|
catch (Throwable t) {
|
||||||
logger.error("Failed to check temperature for thermostat {}", sw.getName());
|
logger.error("Failed to check temperature for thermostat {}", _sw.getName());
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,12 +421,13 @@ public class ZWaveApp {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
for (SwitchTransition tr : transitions) {
|
for (SwitchTransition tr : transitions) {
|
||||||
if (!tr.getSwitch().isHold()) {
|
Switch sw = switches.get(tr.getSwitch().getNodeId());
|
||||||
logger.info("Executing scheduled transition of node {} to level {}", tr.getSwitch().getNodeId(), tr.getLevel());
|
if (!sw.isHold()) {
|
||||||
Globals.app.setSwitchLevel(tr.getSwitch().getNodeId(), tr.getLevel());
|
logger.info("Executing scheduled transition of node {} to level {}", sw.getNodeId(), tr.getLevel());
|
||||||
|
Globals.app.setSwitchLevel(sw.getNodeId(), tr.getLevel());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
logger.info("Skipping scheduled transition of node {} to level {}, switch is on hold", tr.getSwitch().getNodeId(), tr.getLevel());
|
logger.info("Skipping scheduled transition of node {} to level {}, switch is on hold", sw.getNodeId(), tr.getLevel());
|
||||||
ConcurrencyUtils.sleep(100);
|
ConcurrencyUtils.sleep(100);
|
||||||
}
|
}
|
||||||
nextScheduleTask = null;
|
nextScheduleTask = null;
|
||||||
@@ -336,20 +440,20 @@ public class ZWaveApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private double getTemperatureCelsius(Switch _sw) {
|
private double getTemperatureCelsius(Switch _sw) {
|
||||||
if ((pool == null) || (_sw == null) || !(_sw.isThermometer() || _sw.isThermostat()))
|
if ((pool == null) || (_sw == null))
|
||||||
return 0.0;
|
return 0.0;
|
||||||
if (_sw.isUrlThermostat())
|
if (_sw.isThermometerUrlValid())
|
||||||
return DaoSerializer.getDouble(DaoSerializer.parse(pool.executeToString(new HttpGet(_sw.getThermostatSource()))), "temp");
|
return DaoSerializer.getDouble(DaoSerializer.parse(pool.executeToString(new HttpGet(_sw.getThermometerUrl()))), "temp");
|
||||||
else if (_sw.isZWaveThermostat()) {
|
else if (_sw.isZWaveThermostat() && config.isMySwitch(_sw)) {
|
||||||
synchronized (ZWAVE_MUTEX) {
|
synchronized (ZWAVE_MUTEX) {
|
||||||
synchronized (temperatures) {
|
synchronized (sensors) {
|
||||||
controller.send(new MultilevelSensorGetRequest((byte) _sw.getNodeId()));
|
controller.send(new MultilevelSensorGetRequest((byte) _sw.getNodeId()));
|
||||||
try {
|
try {
|
||||||
temperatures.wait(5000);
|
sensors.wait(3000);
|
||||||
} catch (InterruptedException _e) {
|
} catch (InterruptedException _e) {
|
||||||
_e.printStackTrace();
|
_e.printStackTrace();
|
||||||
}
|
}
|
||||||
Double temp = temperatures.get(_sw.getNodeId());
|
Double temp = sensors.get(_sw.getNodeId());
|
||||||
return (temp == null) ? 0.0 : temp;
|
return (temp == null) ? 0.0 : temp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
-230
@@ -1,230 +0,0 @@
|
|||||||
package com.lanternsoftware.zwave.context;
|
|
||||||
|
|
||||||
public class ZWaveSpring {
|
|
||||||
/* private ZWaveConfig config;
|
|
||||||
private static ZWaveSession session;
|
|
||||||
private static Map<Integer, Switch> switches = new HashMap<>();
|
|
||||||
private static Map<Integer, List<Integer>> peers = new HashMap<>();
|
|
||||||
private static Timer timer;
|
|
||||||
private static HttpPool pool;
|
|
||||||
private static SwitchScheduleTask nextScheduleTask;
|
|
||||||
|
|
||||||
public void start() {
|
|
||||||
try {
|
|
||||||
// controller = new Controller();
|
|
||||||
// controller.start("COM4");
|
|
||||||
timer = new Timer("ZWaveApp Timer");
|
|
||||||
pool = new HttpPool(10, 10, 30000, 10000, 10000);
|
|
||||||
session = new LocalZwaveSession();
|
|
||||||
session.connect();
|
|
||||||
while (!session.isNetworkReady()) {
|
|
||||||
System.out.println("Network not ready yet, sleeping");
|
|
||||||
ConcurrencyUtils.sleep(1000);
|
|
||||||
}
|
|
||||||
// session.subscribe(new ZWaveEventListener());
|
|
||||||
|
|
||||||
// for (ZWaveNode node : session.getDeviceManager().getNodes()) {
|
|
||||||
// for (CommandClass cc : node.getCommandClasses()) {
|
|
||||||
// System.out.println(node.getNodeId() + " " + cc.getClassCode() + " " + cc.getLabel());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
//// for (int node = 3; node < 7; node++) {
|
|
||||||
// session.doAction(new ConfigurationSetAction(node, (byte) 7, new byte[]{99}));
|
|
||||||
// ConcurrencyUtils.sleep(100);
|
|
||||||
// session.doAction(new ConfigurationSetAction(node, (byte) 8, new byte[]{0, (byte) 1}));
|
|
||||||
// ConcurrencyUtils.sleep(100);
|
|
||||||
// session.doAction(new ConfigurationSetAction(node, (byte) 9, new byte[]{99}));
|
|
||||||
// ConcurrencyUtils.sleep(100);
|
|
||||||
// session.doAction(new ConfigurationSetAction(node, (byte) 10, new byte[]{0, (byte) 1}));
|
|
||||||
// ConcurrencyUtils.sleep(100);
|
|
||||||
// session.doAction(new ConfigurationSetAction(node, (byte) 11, new byte[]{99}));
|
|
||||||
// ConcurrencyUtils.sleep(100);
|
|
||||||
// session.doAction(new ConfigurationSetAction(node, (byte) 12, new byte[]{0, (byte) 1}));
|
|
||||||
// ConcurrencyUtils.sleep(100);
|
|
||||||
// }
|
|
||||||
} catch (Throwable t) {
|
|
||||||
t.printStackTrace();
|
|
||||||
}
|
|
||||||
config = SerializationEngine.deserialize(ResourceLoader.loadFile(LanternFiles.OPS_PATH + "config.dat"), ZWaveConfig.class, SerializationEngine.SerializationType.JSON);
|
|
||||||
Map<String, List<Integer>> groups = new HashMap<>();
|
|
||||||
for (Switch sw : CollectionUtils.makeNotNull(config.getSwitches())) {
|
|
||||||
switches.put(sw.getNodeId(), sw);
|
|
||||||
CollectionUtils.addToMultiMap(sw.getRoom() + ":" + sw.getName(), sw.getNodeId(), groups);
|
|
||||||
}
|
|
||||||
if (CollectionUtils.filterOne(config.getSwitches(), _sw -> NullUtils.isNotEmpty(_sw.getThermostatSource())) != null) {
|
|
||||||
timer.scheduleAtFixedRate(new ThermostatTask(), 0, 30000);
|
|
||||||
}
|
|
||||||
for (List<Integer> group : groups.values()) {
|
|
||||||
for (Integer node : group) {
|
|
||||||
peers.put(node, CollectionUtils.filter(group, _i -> !_i.equals(node)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
scheduleNextTransition();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void scheduleNextTransition() {
|
|
||||||
TimeZone tz = TimeZone.getTimeZone("America/Chicago");
|
|
||||||
if (nextScheduleTask != null)
|
|
||||||
nextScheduleTask.cancel();
|
|
||||||
Switch next = null;
|
|
||||||
SwitchTransition transition = null;
|
|
||||||
Date transitionDate = null;
|
|
||||||
for (Switch sw : switches.values()) {
|
|
||||||
for (SwitchTransition t : CollectionUtils.makeNotNull(sw.getSchedule())) {
|
|
||||||
Date nextTransition = t.getNextTransition(tz);
|
|
||||||
if ((transitionDate == null) || nextTransition.before(transitionDate)) {
|
|
||||||
transitionDate = nextTransition;
|
|
||||||
transition = t;
|
|
||||||
next = sw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (transitionDate != null) {
|
|
||||||
System.out.println("Next transition scheduled for node " + next.getNodeId() + " to level " + transition.getLevel() + " at " + DateUtils.format(tz, transitionDate, "hh:mm:ssa"));
|
|
||||||
nextScheduleTask = new SwitchScheduleTask(next, transition);
|
|
||||||
timer.schedule(nextScheduleTask, transitionDate);
|
|
||||||
} else
|
|
||||||
nextScheduleTask = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSwitchLevel(int _nodeId, int _level) {
|
|
||||||
Switch sw = switches.get(_nodeId);
|
|
||||||
if ((sw == null) || !sw.isPrimary())
|
|
||||||
return;
|
|
||||||
sw.setLevel(_level);
|
|
||||||
if (NullUtils.isEmpty(sw.getThermostatSource())) {
|
|
||||||
doGroupSwitchAction(_nodeId, _level, sw.isMultilevel());
|
|
||||||
} else {
|
|
||||||
if (timer != null)
|
|
||||||
timer.schedule(new ThermostatTask(), 0);
|
|
||||||
persistConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSwitchSchedule(int _nodeId, List<SwitchTransition> _transitions) {
|
|
||||||
Switch sw = switches.get(_nodeId);
|
|
||||||
if ((sw == null) || !sw.isPrimary())
|
|
||||||
return;
|
|
||||||
sw.setSchedule(_transitions);
|
|
||||||
persistConfig();
|
|
||||||
scheduleNextTransition();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSwitchHold(int _nodeId, boolean _hold) {
|
|
||||||
Switch sw = switches.get(_nodeId);
|
|
||||||
if ((sw == null) || !sw.isPrimary())
|
|
||||||
return;
|
|
||||||
sw.setHold(_hold);
|
|
||||||
persistConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void persistConfig() {
|
|
||||||
synchronized (this) {
|
|
||||||
ResourceLoader.writeFile(LanternFiles.OPS_PATH + "config.dat", SerializationEngine.serialize(config, SerializationEngine.SerializationType.JSON));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSwitchLevel(int _nodeId) {
|
|
||||||
Switch sw = switches.get(_nodeId);
|
|
||||||
return (sw != null) ? sw.getLevel() : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ZWaveConfig getConfig() {
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stop() {
|
|
||||||
session.shutdown();
|
|
||||||
if (timer != null) {
|
|
||||||
timer.cancel();
|
|
||||||
timer = null;
|
|
||||||
}
|
|
||||||
if (pool != null) {
|
|
||||||
pool.shutdown();
|
|
||||||
pool = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
public static class ZWaveEventListener implements EventHandler {
|
|
||||||
@EventSubscribe
|
|
||||||
public void receive(ZWaveEvent event) throws Exception {
|
|
||||||
if (event instanceof ApplicationCommandEvent) {
|
|
||||||
ApplicationCommandEvent ace = (ApplicationCommandEvent) event;
|
|
||||||
if (ace.getCommandClass() == CommandClass.SWITCH_MULTILEVEL) {
|
|
||||||
for (Integer node : CollectionUtils.makeNotNull(peers.get(ace.getNodeId()))) {
|
|
||||||
Switch sw = switches.get(node);
|
|
||||||
System.out.println("Mirror Event from node " + ((ApplicationCommandEvent) event).getNodeId() + " to node " + node);
|
|
||||||
// session.doAction(new SwitchAction(node, ace.getPayload()[1], sw == null || sw.isMultilevel()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventSubscribe
|
|
||||||
public void handleSensorEvent(DeviceSensorEvent sensorEvent) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void doGroupSwitchAction(int _primary, int _level, boolean _multilevel) {
|
|
||||||
List<Integer> nodes = CollectionUtils.asArrayList(_primary);
|
|
||||||
nodes.addAll(CollectionUtils.makeNotNull(peers.get(_primary)));
|
|
||||||
for (int node : nodes) {
|
|
||||||
try {
|
|
||||||
session.doAction(new SwitchAction(node, _level, _multilevel));
|
|
||||||
} catch (HomeAutomationException _e) {
|
|
||||||
_e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ThermostatTask extends TimerTask {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
for (Switch sw : switches.values()) {
|
|
||||||
if (NullUtils.isNotEmpty(sw.getThermostatSource())) {
|
|
||||||
double tempF = getTemperatureCelsius(sw) * 1.8 + 32;
|
|
||||||
if (tempF > sw.getLevel() + 0.4) {
|
|
||||||
doGroupSwitchAction(sw.getNodeId(), 0, false);
|
|
||||||
System.out.println("Turning " + sw.getRoom() + " " + sw.getName() + " off, temp is: " + tempF + " set to: " + sw.getLevel());
|
|
||||||
} else if (tempF < sw.getLevel() - 0.4) {
|
|
||||||
doGroupSwitchAction(sw.getNodeId(), (byte) 0xf, false);
|
|
||||||
System.out.println("Turning " + sw.getRoom() + " " + sw.getName() + " on, temp is: " + tempF + " set to: " + sw.getLevel());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class SwitchScheduleTask extends TimerTask {
|
|
||||||
private final Switch sw;
|
|
||||||
private final SwitchTransition transition;
|
|
||||||
|
|
||||||
public SwitchScheduleTask(Switch _sw, SwitchTransition _transition) {
|
|
||||||
sw = _sw;
|
|
||||||
transition = _transition;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
System.out.println("Executing scheduled transition of node " + sw.getNodeId() + " to level " + transition.getLevel());
|
|
||||||
if (!sw.isHold()) {
|
|
||||||
Globals.app.setSwitchLevel(sw.getNodeId(), transition.getLevel());
|
|
||||||
}
|
|
||||||
nextScheduleTask = null;
|
|
||||||
Globals.app.scheduleNextTransition();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getTemperatureCelsius(int _nodeId) {
|
|
||||||
return getTemperatureCelsius(switches.get(_nodeId));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static double getTemperatureCelsius(Switch _sw) {
|
|
||||||
if ((pool == null) || (_sw == null) || NullUtils.isEmpty(_sw.getThermostatSource()))
|
|
||||||
return 0.0;
|
|
||||||
return BsonUtils.getDouble(BsonUtils.parse(pool.executeToString(new HttpGet(_sw.getThermostatSource()))), "temp");
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
+1
@@ -12,6 +12,7 @@ public class MongoZWaveDao implements ZWaveDao {
|
|||||||
proxy = new MongoProxy(_config);
|
proxy = new MongoProxy(_config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void shutdown() {
|
public void shutdown() {
|
||||||
proxy.shutdown();
|
proxy.shutdown();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,4 +5,5 @@ import com.lanternsoftware.datamodel.zwave.ZWaveConfig;
|
|||||||
public interface ZWaveDao {
|
public interface ZWaveDao {
|
||||||
void putConfig(ZWaveConfig _config);
|
void putConfig(ZWaveConfig _config);
|
||||||
ZWaveConfig getConfig(int _accountId);
|
ZWaveConfig getConfig(int _accountId);
|
||||||
|
void shutdown();
|
||||||
}
|
}
|
||||||
|
|||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
package com.lanternsoftware.zwave.relay;
|
||||||
|
|
||||||
|
import com.pi4j.io.gpio.GpioFactory;
|
||||||
|
import com.pi4j.io.gpio.GpioPinDigitalOutput;
|
||||||
|
import com.pi4j.io.gpio.PinState;
|
||||||
|
import com.pi4j.io.gpio.RaspiPin;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class RelayController {
|
||||||
|
protected static final Logger LOG = LoggerFactory.getLogger(RelayController.class);
|
||||||
|
|
||||||
|
private final Map<Integer, GpioPinDigitalOutput> pins = new HashMap<>();
|
||||||
|
|
||||||
|
public void setRelay(int _pin, boolean _on) {
|
||||||
|
GpioPinDigitalOutput pin = pins.get(_pin);
|
||||||
|
if (pin == null) {
|
||||||
|
pin = GpioFactory.getInstance().provisionDigitalOutputPin(RaspiPin.getPinByAddress(_pin), "Relay", PinState.LOW);
|
||||||
|
if (pin != null)
|
||||||
|
pins.put(_pin, pin);
|
||||||
|
else {
|
||||||
|
LOG.error("Failed to get pin {}", _pin);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_on)
|
||||||
|
pin.high();
|
||||||
|
else
|
||||||
|
pin.low();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shutdown() {
|
||||||
|
GpioFactory.getInstance().shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
+52
@@ -0,0 +1,52 @@
|
|||||||
|
package com.lanternsoftware.zwave.security;
|
||||||
|
|
||||||
|
import com.lanternsoftware.datamodel.zwave.Switch;
|
||||||
|
import com.pi4j.io.gpio.GpioFactory;
|
||||||
|
import com.pi4j.io.gpio.GpioPinDigitalInput;
|
||||||
|
import com.pi4j.io.gpio.PinPullResistance;
|
||||||
|
import com.pi4j.io.gpio.RaspiPin;
|
||||||
|
import com.pi4j.io.gpio.event.GpioPinListenerDigital;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class SecurityController {
|
||||||
|
protected static final Logger LOG = LoggerFactory.getLogger(SecurityController.class);
|
||||||
|
|
||||||
|
private final Map<Integer, GpioPinDigitalInput> pins = new HashMap<>();
|
||||||
|
|
||||||
|
public boolean isOpen(int _pin) {
|
||||||
|
GpioPinDigitalInput pin = getPin(_pin);
|
||||||
|
return (pin == null) || pin.getState().isHigh();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void listen(Switch _sw, SecurityListener _listener) {
|
||||||
|
GpioPinDigitalInput pin = getPin(_sw.getGpioPin());
|
||||||
|
if (pin != null)
|
||||||
|
pin.addListener((GpioPinListenerDigital) _event -> _listener.onStateChanged(_sw.getNodeId(), _event.getState().isHigh()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private GpioPinDigitalInput getPin(int _pin) {
|
||||||
|
GpioPinDigitalInput pin = pins.get(_pin);
|
||||||
|
if (pin == null) {
|
||||||
|
pin = GpioFactory.getInstance().provisionDigitalInputPin(RaspiPin.getPinByAddress(_pin), "SecuritySensor", PinPullResistance.PULL_UP);
|
||||||
|
if (pin != null)
|
||||||
|
pins.put(_pin, pin);
|
||||||
|
else {
|
||||||
|
LOG.error("Failed to get pin {}", _pin);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shutdown() {
|
||||||
|
for (GpioPinDigitalInput pin : pins.values()) {
|
||||||
|
pin.removeAllListeners();
|
||||||
|
}
|
||||||
|
pins.clear();
|
||||||
|
GpioFactory.getInstance().shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
package com.lanternsoftware.zwave.security;
|
||||||
|
|
||||||
|
public interface SecurityListener {
|
||||||
|
void onStateChanged(int nodeId, boolean _open);
|
||||||
|
}
|
||||||
+10
-4
@@ -1,16 +1,22 @@
|
|||||||
package com.lanternsoftware.zwave.servlet;
|
package com.lanternsoftware.zwave.servlet;
|
||||||
|
|
||||||
import com.lanternsoftware.datamodel.currentmonitor.AuthCode;
|
import com.lanternsoftware.datamodel.currentmonitor.AuthCode;
|
||||||
|
import com.lanternsoftware.util.LanternFiles;
|
||||||
|
import com.lanternsoftware.util.ResourceLoader;
|
||||||
|
import com.lanternsoftware.util.cryptography.AESTool;
|
||||||
|
import com.lanternsoftware.util.dao.DaoSerializer;
|
||||||
import com.lanternsoftware.zwave.context.Globals;
|
import com.lanternsoftware.zwave.context.Globals;
|
||||||
|
import com.lanternsoftware.zwave.context.ZWaveApp;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
public abstract class SecureServlet extends ZWaveServlet {
|
public abstract class SecureServlet extends ZWaveServlet {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doGet(HttpServletRequest _req, HttpServletResponse _rep) {
|
protected void doGet(HttpServletRequest _req, HttpServletResponse _rep) {
|
||||||
AuthCode authCode = Globals.cmDao.decryptAuthCode(_req.getHeader("auth_code"));
|
AuthCode authCode = DaoSerializer.fromZipBson(ZWaveApp.aes.decryptFromBase64(_req.getHeader("auth_code")), AuthCode.class);
|
||||||
if ((authCode == null) || (authCode.getAccountId() != 1)) {
|
if ((authCode == null) || (authCode.getAccountId() != 100)) {
|
||||||
_rep.setStatus(401);
|
_rep.setStatus(401);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -22,8 +28,8 @@ public abstract class SecureServlet extends ZWaveServlet {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doPost(HttpServletRequest _req, HttpServletResponse _rep) {
|
protected void doPost(HttpServletRequest _req, HttpServletResponse _rep) {
|
||||||
AuthCode authCode = Globals.cmDao.decryptAuthCode(_req.getHeader("auth_code"));
|
AuthCode authCode = DaoSerializer.fromZipBson(ZWaveApp.aes.decryptFromBase64(_req.getHeader("auth_code")), AuthCode.class);
|
||||||
if ((authCode == null) || (authCode.getAccountId() != 1)) {
|
if ((authCode == null) || (authCode.getAccountId() != 100)) {
|
||||||
_rep.setStatus(401);
|
_rep.setStatus(401);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
+4
@@ -1,6 +1,7 @@
|
|||||||
package com.lanternsoftware.zwave.servlet;
|
package com.lanternsoftware.zwave.servlet;
|
||||||
|
|
||||||
import com.lanternsoftware.datamodel.currentmonitor.AuthCode;
|
import com.lanternsoftware.datamodel.currentmonitor.AuthCode;
|
||||||
|
import com.lanternsoftware.datamodel.zwave.Switch;
|
||||||
import com.lanternsoftware.datamodel.zwave.SwitchSchedule;
|
import com.lanternsoftware.datamodel.zwave.SwitchSchedule;
|
||||||
import com.lanternsoftware.datamodel.zwave.ThermostatMode;
|
import com.lanternsoftware.datamodel.zwave.ThermostatMode;
|
||||||
import com.lanternsoftware.util.CollectionUtils;
|
import com.lanternsoftware.util.CollectionUtils;
|
||||||
@@ -49,5 +50,8 @@ public class SwitchServlet extends SecureServlet {
|
|||||||
Globals.app.setSwitchSchedule(nodeId, transitions);
|
Globals.app.setSwitchSchedule(nodeId, transitions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
Globals.app.updateSwitch(getRequestPayload(_req, Switch.class));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
@@ -80,6 +80,9 @@ public abstract class ZWaveServlet extends HttpServlet {
|
|||||||
IOUtils.closeQuietly(is);
|
IOUtils.closeQuietly(is);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
protected <T> T getRequestPayload(HttpServletRequest _req, Class<T> _retClass) {
|
||||||
|
return DaoSerializer.fromZipBson(getRequestPayload(_req), _retClass);
|
||||||
|
}
|
||||||
|
|
||||||
protected String[] path(HttpServletRequest _req) {
|
protected String[] path(HttpServletRequest _req) {
|
||||||
return NullUtils.cleanSplit(NullUtils.makeNotNull(_req.getPathInfo()), "/");
|
return NullUtils.cleanSplit(NullUtils.makeNotNull(_req.getPathInfo()), "/");
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.neuronrobotics</groupId>
|
<groupId>com.neuronrobotics</groupId>
|
||||||
<artifactId>nrjavaserial</artifactId>
|
<artifactId>nrjavaserial</artifactId>
|
||||||
<version>3.15.0</version>
|
<version>5.2.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
@@ -60,6 +60,46 @@
|
|||||||
<target>1.8</target>
|
<target>1.8</target>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
<version>3.2.1</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-zwave</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.zwave.PortEnum</Main-Class>
|
||||||
|
<Specification-Title>Lantern ZWave</Specification-Title>
|
||||||
|
<Specification-Version>${project.version}</Specification-Version>
|
||||||
|
<Specification-Vendor>Lantern Software, Inc.</Specification-Vendor>
|
||||||
|
</manifestEntries>
|
||||||
|
</transformer>
|
||||||
|
</transformers>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package com.lanternsoftware.zwave;
|
||||||
|
|
||||||
|
import gnu.io.CommPortIdentifier;
|
||||||
|
|
||||||
|
import java.util.Enumeration;
|
||||||
|
|
||||||
|
public class PortEnum {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
Enumeration<CommPortIdentifier> e = CommPortIdentifier.getPortIdentifiers();
|
||||||
|
while (e.hasMoreElements()) {
|
||||||
|
CommPortIdentifier id = e.nextElement();
|
||||||
|
if (id != null) {
|
||||||
|
System.out.println(id.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -70,7 +70,7 @@ public enum CommandClass {
|
|||||||
TIME_PARAMETERS((byte)0x8B, "TIME_PARAMETERS"),
|
TIME_PARAMETERS((byte)0x8B, "TIME_PARAMETERS"),
|
||||||
GEOGRAPHIC_LOCATION((byte)0x8C, "GEOGRAPHIC_LOCATION"),
|
GEOGRAPHIC_LOCATION((byte)0x8C, "GEOGRAPHIC_LOCATION"),
|
||||||
COMPOSITE((byte)0x8D, "COMPOSITE"),
|
COMPOSITE((byte)0x8D, "COMPOSITE"),
|
||||||
MULTI_INSTANCE_ASSOCIATION((byte)0x8E, "MULTI_INSTANCE_ASSOCIATION"),
|
MULTI_CHANNEL_ASSOCIATION((byte)0x8E, "MULTI_CHANNEL_ASSOCIATION"),
|
||||||
MULTI_CMD((byte)0x8F, "MULTI_CMD"),
|
MULTI_CMD((byte)0x8F, "MULTI_CMD"),
|
||||||
ENERGY_PRODUCTION((byte)0x90, "ENERGY_PRODUCTION"),
|
ENERGY_PRODUCTION((byte)0x90, "ENERGY_PRODUCTION"),
|
||||||
MANUFACTURER_PROPRIETARY((byte)0x91, "MANUFACTURER_PROPRIETARY"),
|
MANUFACTURER_PROPRIETARY((byte)0x91, "MANUFACTURER_PROPRIETARY"),
|
||||||
|
|||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
package com.lanternsoftware.zwave.message.impl;
|
||||||
|
|
||||||
|
import com.lanternsoftware.zwave.message.CommandClass;
|
||||||
|
import com.lanternsoftware.zwave.message.ControllerMessageType;
|
||||||
|
import com.lanternsoftware.zwave.message.RequestMessage;
|
||||||
|
|
||||||
|
public class AssociationGetRequest extends RequestMessage {
|
||||||
|
public AssociationGetRequest() {
|
||||||
|
this((byte)0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AssociationGetRequest(byte _nodeId) {
|
||||||
|
super(_nodeId, ControllerMessageType.SendData, CommandClass.ASSOCIATION, (byte)0x02);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String describe() {
|
||||||
|
return name() + " node: " + nodeId;
|
||||||
|
}
|
||||||
|
}
|
||||||
+56
@@ -0,0 +1,56 @@
|
|||||||
|
package com.lanternsoftware.zwave.message.impl;
|
||||||
|
|
||||||
|
import com.lanternsoftware.zwave.message.CommandClass;
|
||||||
|
import com.lanternsoftware.zwave.message.ControllerMessageType;
|
||||||
|
import com.lanternsoftware.zwave.message.RequestMessage;
|
||||||
|
|
||||||
|
public class AssociationReportRequest extends RequestMessage {
|
||||||
|
private byte groupIdx;
|
||||||
|
private byte maxAssociations;
|
||||||
|
private byte numReportsToFollow;
|
||||||
|
|
||||||
|
public AssociationReportRequest() {
|
||||||
|
this((byte) 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AssociationReportRequest(byte _nodeId) {
|
||||||
|
super(_nodeId, ControllerMessageType.ApplicationCommandHandler, CommandClass.ASSOCIATION, (byte) 0x03);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fromPayload(byte[] _payload) {
|
||||||
|
nodeId = _payload[5];
|
||||||
|
groupIdx = _payload[8];
|
||||||
|
maxAssociations = _payload[9];
|
||||||
|
numReportsToFollow = _payload[10];
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getGroupIdx() {
|
||||||
|
return groupIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGroupIdx(byte _groupIdx) {
|
||||||
|
groupIdx = _groupIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getMaxAssociations() {
|
||||||
|
return maxAssociations;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxAssociations(byte _maxAssociations) {
|
||||||
|
maxAssociations = _maxAssociations;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getNumReportsToFollow() {
|
||||||
|
return numReportsToFollow;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNumReportsToFollow(byte _numReportsToFollow) {
|
||||||
|
numReportsToFollow = _numReportsToFollow;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String describe() {
|
||||||
|
return name() + " node: " + nodeId;
|
||||||
|
}
|
||||||
|
}
|
||||||
+45
@@ -0,0 +1,45 @@
|
|||||||
|
package com.lanternsoftware.zwave.message.impl;
|
||||||
|
|
||||||
|
import com.lanternsoftware.zwave.message.CommandClass;
|
||||||
|
import com.lanternsoftware.zwave.message.SendDataRequestMessage;
|
||||||
|
|
||||||
|
public class AssociationSetRequest extends SendDataRequestMessage {
|
||||||
|
private byte groupIdx;
|
||||||
|
private byte targetNodeId;
|
||||||
|
|
||||||
|
public AssociationSetRequest() {
|
||||||
|
this((byte)0, (byte)0, (byte)0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AssociationSetRequest(byte _nodeId, byte _groupIdx, byte _targetNodeId) {
|
||||||
|
super(_nodeId, CommandClass.ASSOCIATION, (byte) 0x01);
|
||||||
|
groupIdx = _groupIdx;
|
||||||
|
targetNodeId = _targetNodeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getGroupIdx() {
|
||||||
|
return groupIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGroupIdx(byte _groupIdx) {
|
||||||
|
groupIdx = _groupIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getTargetNodeId() {
|
||||||
|
return targetNodeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTargetNodeId(byte _targetNodeId) {
|
||||||
|
targetNodeId = _targetNodeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getPayload() {
|
||||||
|
return asByteArray(groupIdx, targetNodeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String describe() {
|
||||||
|
return name() + " node: " + nodeId + " groupIdx: " + groupIdx + " targetNodeIdx: " + targetNodeId;
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
@@ -1,4 +1,6 @@
|
|||||||
com.lanternsoftware.zwave.message.impl.ApplicationUpdateRequest
|
com.lanternsoftware.zwave.message.impl.ApplicationUpdateRequest
|
||||||
|
com.lanternsoftware.zwave.message.impl.AssociationGetRequest
|
||||||
|
com.lanternsoftware.zwave.message.impl.AssociationReportRequest
|
||||||
com.lanternsoftware.zwave.message.impl.BinarySwitchSetRequest
|
com.lanternsoftware.zwave.message.impl.BinarySwitchSetRequest
|
||||||
com.lanternsoftware.zwave.message.impl.BinarySwitchReportRequest
|
com.lanternsoftware.zwave.message.impl.BinarySwitchReportRequest
|
||||||
com.lanternsoftware.zwave.message.impl.ByteMessage
|
com.lanternsoftware.zwave.message.impl.ByteMessage
|
||||||
|
|||||||
Reference in New Issue
Block a user