Added config settings page and refactored backup handling and bridge

settings and cotntrol. Next is to add the editing to the config screen.
This commit is contained in:
Admin
2016-02-11 16:51:11 -06:00
parent 20328b15d8
commit e6da9950d6
25 changed files with 739 additions and 466 deletions

View File

@@ -4,19 +4,12 @@ import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.nio.file.DirectoryStream;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Enumeration;
import java.util.List;
import org.apache.http.conn.util.InetAddressUtils;
import org.slf4j.Logger;
@@ -24,146 +17,139 @@ import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
public class BridgeSettings {
private String upnpconfigaddress;
private String serverport;
private String upnpresponseport;
private String upnpdevicedb;
private IpList veraaddress;
private IpList harmonyaddress;
private String harmonyuser;
private String harmonypwd;
private Integer buttonsleep;
private boolean upnpstrict;
private boolean traceupnp;
private boolean devmode;
private String nestuser;
private String nestpwd;
private boolean veraconfigured;
private boolean harmonyconfigured;
private boolean nestconfigured;
private String configfile;
private boolean restart;
public class BridgeSettings extends BackupHandler {
private BridgeSettingsDescriptor theBridgeSettings;
private boolean reinit;
private boolean stop;
public BridgeSettings() {
super();
this.upnpstrict = true;
this.devmode = false;
this.traceupnp = false;
this.restart = false;
this.reinit = false;
this.stop = false;
this.nestconfigured = false;
this.veraconfigured = false;
this.harmonyconfigured = false;
theBridgeSettings = new BridgeSettingsDescriptor();
theBridgeSettings.setUpnpStrict(true);
theBridgeSettings.setDevMode(false);
theBridgeSettings.setTraceupnp(false);
theBridgeSettings.setNestConfigured(false);
theBridgeSettings.setVeraconfigured(false);
theBridgeSettings.setHarmonyconfigured(false);
}
public BridgeSettingsDescriptor getBridgeSettingsDescriptor() {
return theBridgeSettings;
}
public String getUpnpConfigAddress() {
return upnpconfigaddress;
return theBridgeSettings.getUpnpConfigAddress();
}
public void setUpnpConfigAddress(String upnpConfigAddress) {
this.upnpconfigaddress = upnpConfigAddress;
theBridgeSettings.setUpnpConfigAddress(upnpConfigAddress);
}
public String getServerPort() {
return serverport;
return theBridgeSettings.getServerPort();
}
public void setServerPort(String serverPort) {
this.serverport = serverPort;
theBridgeSettings.setServerPort(serverPort);
}
public String getUpnpResponsePort() {
return upnpresponseport;
return theBridgeSettings.getUpnpResponsePort();
}
public void setUpnpResponsePort(String upnpResponsePort) {
this.upnpresponseport = upnpResponsePort;
theBridgeSettings.setUpnpResponsePort(upnpResponsePort);
}
public String getUpnpDeviceDb() {
return upnpdevicedb;
return theBridgeSettings.getUpnpDeviceDb();
}
public void setUpnpDeviceDb(String upnpDeviceDb) {
this.upnpdevicedb = upnpDeviceDb;
theBridgeSettings.setUpnpDeviceDb(upnpDeviceDb);
}
public IpList getVeraAddress() {
return veraaddress;
return theBridgeSettings.getVeraAddress();
}
public void setVeraAddress(IpList veraAddress) {
this.veraaddress = veraAddress;
theBridgeSettings.setVeraAddress(veraAddress);
}
public IpList getHarmonyAddress() {
return harmonyaddress;
return theBridgeSettings.getHarmonyAddress();
}
public void setHarmonyAddress(IpList harmonyaddress) {
this.harmonyaddress = harmonyaddress;
theBridgeSettings.setHarmonyAddress(harmonyaddress);
}
public String getHarmonyUser() {
return harmonyuser;
return theBridgeSettings.getHarmonyUser();
}
public void setHarmonyUser(String harmonyuser) {
this.harmonyuser = harmonyuser;
theBridgeSettings.setHarmonyUser(harmonyuser);
}
public String getHarmonyPwd() {
return harmonypwd;
return theBridgeSettings.getHarmonyPwd();
}
public void setHarmonyPwd(String harmonypwd) {
this.harmonypwd = harmonypwd;
theBridgeSettings.setHarmonyPwd(harmonypwd);
}
public boolean isUpnpStrict() {
return upnpstrict;
return theBridgeSettings.isUpnpStrict();
}
public void setUpnpStrict(boolean upnpStrict) {
this.upnpstrict = upnpStrict;
theBridgeSettings.setUpnpStrict(upnpStrict);
}
public boolean isTraceupnp() {
return traceupnp;
return theBridgeSettings.isTraceupnp();
}
public void setTraceupnp(boolean traceupnp) {
this.traceupnp = traceupnp;
theBridgeSettings.setTraceupnp(traceupnp);
}
public boolean isDevMode() {
return devmode;
return theBridgeSettings.isDevMode();
}
public void setDevMode(boolean devmode) {
this.devmode = devmode;
theBridgeSettings.setDevMode(devmode);
}
public String getNestuser() {
return nestuser;
return theBridgeSettings.getNestuser();
}
public void setNestuser(String nestuser) {
this.nestuser = nestuser;
theBridgeSettings.setNestuser(nestuser);
}
public String getNestpwd() {
return nestpwd;
return theBridgeSettings.getNestpwd();
}
public void setNestpwd(String nestpwd) {
this.nestpwd = nestpwd;
theBridgeSettings.setNestpwd(nestpwd);
}
public boolean isVeraconfigured() {
return veraconfigured;
return theBridgeSettings.isVeraconfigured();
}
public void setVeraconfigured(boolean veraconfigured) {
this.veraconfigured = veraconfigured;
theBridgeSettings.setVeraconfigured(veraconfigured);
}
public boolean isHarmonyconfigured() {
return harmonyconfigured;
return theBridgeSettings.isHarmonyconfigured();
}
public void setHarmonyconfigured(boolean harmonyconfigured) {
this.harmonyconfigured = harmonyconfigured;
theBridgeSettings.setHarmonyconfigured(harmonyconfigured);
}
public boolean isNestConfigured() {
return nestconfigured;
return theBridgeSettings.isNestConfigured();
}
public void setNestConfigured(boolean isNestConfigured) {
this.nestconfigured = isNestConfigured;
theBridgeSettings.setNestConfigured(isNestConfigured);
}
public Integer getButtonsleep() {
return buttonsleep;
return theBridgeSettings.getButtonsleep();
}
public void setButtonsleep(Integer buttonsleep) {
this.buttonsleep = buttonsleep;
theBridgeSettings.setButtonsleep(buttonsleep);
}
public boolean isRestart() {
return restart;
public String getConfigfile() {
return theBridgeSettings.getConfigfile();
}
public void setRestart(boolean restart) {
this.restart = restart;
public void setConfigfile(String configfile) {
theBridgeSettings.setConfigfile(configfile);
}
public boolean isReinit() {
return reinit;
}
public void setReinit(boolean reinit) {
this.reinit = reinit;
}
public boolean isStop() {
return stop;
@@ -171,39 +157,6 @@ public class BridgeSettings {
public void setStop(boolean stop) {
this.stop = stop;
}
public String getConfigfile() {
return configfile;
}
public void setConfigfile(String configfile) {
this.configfile = configfile;
}
public Boolean isValidVera() {
if(this.veraaddress == null)
return false;
List<NamedIP> devicesList = this.veraaddress.getDevices();
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
return false;
return true;
}
public Boolean isValidHarmony() {
if(this.harmonyaddress == null)
return false;
List<NamedIP> devicesList = this.harmonyaddress.getDevices();
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
return false; if(this.harmonypwd == null || this.harmonypwd == "")
return false;
if(this.harmonyuser == null || this.harmonyuser == "")
return false;
return true;
}
public Boolean isValidNest() {
if(this.nestpwd == null || this.nestpwd == "")
return false;
if(this.nestuser == null || this.nestuser == "")
return false;
return true;
}
public void buildSettings() {
Logger log = LoggerFactory.getLogger(BridgeSettings.class);
InetAddress address = null;
@@ -314,8 +267,17 @@ public class BridgeSettings {
if(this.getButtonsleep() <= 0)
this.setButtonsleep(Integer.parseInt(Configuration.DFAULT_BUTTON_SLEEP));
this.setVeraconfigured(theBridgeSettings.isValidVera());
this.setHarmonyconfigured(theBridgeSettings.isValidHarmony());
this.setNestConfigured(theBridgeSettings.isValidNest());
setupParams(Paths.get(getConfigfile()), ".cfgbk", "habridge.config-");
}
public void loadConfig() {
if(getConfigfile() != null)
_loadConfig();
}
private void _loadConfig() {
Path configPath = Paths.get(getConfigfile());
_loadConfig(configPath);
@@ -323,7 +285,7 @@ public class BridgeSettings {
private void _loadConfig(Path aPath) {
String jsonContent = configReader(aPath);
BridgeSettings aBridgeSettings = new Gson().fromJson(jsonContent, BridgeSettings.class);
BridgeSettingsDescriptor aBridgeSettings = new Gson().fromJson(jsonContent, BridgeSettingsDescriptor.class);
this.setButtonsleep(aBridgeSettings.getButtonsleep());
this.setUpnpConfigAddress(aBridgeSettings.getUpnpConfigAddress());
this.setServerPort(aBridgeSettings.getServerPort());
@@ -338,18 +300,19 @@ public class BridgeSettings {
this.setDevMode(aBridgeSettings.isDevMode());
this.setNestuser(aBridgeSettings.getNestuser());
this.setNestpwd(aBridgeSettings.getNestpwd());
this.setVeraconfigured(aBridgeSettings.isVeraconfigured());
this.setHarmonyconfigured(aBridgeSettings.isHarmonyconfigured());
this.setNestConfigured(aBridgeSettings.isNestConfigured());
this.setVeraconfigured(aBridgeSettings.isValidVera());
this.setHarmonyconfigured(aBridgeSettings.isValidHarmony());
this.setNestConfigured(aBridgeSettings.isValidNest());
}
public void save() {
public void save(BridgeSettings newBridgeSettings) {
Logger log = LoggerFactory.getLogger(BridgeSettings.class);
log.debug("Save HA Bridge settings.");
Path configPath = Paths.get(getConfigfile());
JsonTransformer aRenderer = new JsonTransformer();
String jsonValue = aRenderer.render(this);
String jsonValue = aRenderer.render(newBridgeSettings);
configWriter(jsonValue, configPath);
log.debug("Save HA Bridge settings.");
_loadConfig(configPath);
}
@@ -371,7 +334,7 @@ public class BridgeSettings {
try {
Path target = null;
if(Files.exists(filePath)) {
target = FileSystems.getDefault().getPath(filePath.getParent().toString(), "device.db.old");
target = FileSystems.getDefault().getPath(filePath.getParent().toString(), "habridge.config.old");
Files.move(filePath, target);
}
Files.write(filePath, content.getBytes(), StandardOpenOption.CREATE);
@@ -400,72 +363,4 @@ public class BridgeSettings {
return content;
}
public String backupConfig(String aFilename) {
Logger log = LoggerFactory.getLogger(BridgeSettings.class);
Path configPath = Paths.get(getConfigfile());
if(aFilename == null || aFilename.equalsIgnoreCase("")) {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
aFilename = "habridge.config-" + dateFormat.format(Calendar.getInstance().getTime()) + ".bk";
}
else
aFilename = aFilename + ".bk";
try {
Files.copy(configPath, FileSystems.getDefault().getPath(configPath.getParent().toString(), aFilename), StandardCopyOption.COPY_ATTRIBUTES);
} catch (IOException e) {
log.error("Could not backup to file: " + aFilename + " message: " + e.getMessage(), e);
}
log.debug("Backup config: " + aFilename);
return aFilename;
}
public String deleteConfigBackup(String aFilename) {
Logger log = LoggerFactory.getLogger(BridgeSettings.class);
Path configPath = Paths.get(getConfigfile());
log.debug("Delete backup config: " + aFilename);
try {
Files.delete(FileSystems.getDefault().getPath(configPath.getParent().toString(), aFilename));
} catch (IOException e) {
log.error("Could not delete file: " + aFilename + " message: " + e.getMessage(), e);
}
return aFilename;
}
public String restoreConfigBackup(String aFilename) {
Logger log = LoggerFactory.getLogger(BridgeSettings.class);
Path configPath = Paths.get(getConfigfile());
log.debug("Restore backup config: " + aFilename);
try {
Path target = null;
if(Files.exists(configPath)) {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
target = FileSystems.getDefault().getPath(configPath.getParent().toString(), "habridge.config-" + dateFormat.format(Calendar.getInstance().getTime()) + ".bk");
Files.move(configPath, target);
}
Files.copy(FileSystems.getDefault().getPath(configPath.getParent().toString(), aFilename), configPath, StandardCopyOption.COPY_ATTRIBUTES);
} catch (IOException e) {
log.error("Error restoring the file: " + aFilename + " message: " + e.getMessage(), e);
return null;
}
_loadConfig(configPath);
return aFilename;
}
public List<String> getConfigBackups() {
Logger log = LoggerFactory.getLogger(BridgeSettings.class);
Path configPath = Paths.get(getConfigfile());
List<String> theFilenames = new ArrayList<String>();
Path dir = configPath.getParent();
try (DirectoryStream<Path> stream =
Files.newDirectoryStream(dir, "*.{bk}")) {
for (Path entry: stream) {
theFilenames.add(entry.getFileName().toString());
}
} catch (IOException x) {
// IOException can never be thrown by the iteration.
// In this snippet, it can // only be thrown by newDirectoryStream.
log.error("Issue getting directory listing for config backups - " + x.getMessage());
}
return theFilenames;
}
}

View File

@@ -0,0 +1,170 @@
package com.bwssystems.HABridge;
import java.util.List;
public class BridgeSettingsDescriptor {
private String upnpconfigaddress;
private String serverport;
private String upnpresponseport;
private String upnpdevicedb;
private IpList veraaddress;
private IpList harmonyaddress;
private String harmonyuser;
private String harmonypwd;
private Integer buttonsleep;
private boolean upnpstrict;
private boolean traceupnp;
private boolean devmode;
private String nestuser;
private String nestpwd;
private boolean veraconfigured;
private boolean harmonyconfigured;
private boolean nestconfigured;
private String configfile;
public BridgeSettingsDescriptor() {
super();
this.upnpstrict = true;
this.devmode = false;
this.traceupnp = false;
this.nestconfigured = false;
this.veraconfigured = false;
this.harmonyconfigured = false;
}
public String getUpnpConfigAddress() {
return upnpconfigaddress;
}
public void setUpnpConfigAddress(String upnpConfigAddress) {
this.upnpconfigaddress = upnpConfigAddress;
}
public String getServerPort() {
return serverport;
}
public void setServerPort(String serverPort) {
this.serverport = serverPort;
}
public String getUpnpResponsePort() {
return upnpresponseport;
}
public void setUpnpResponsePort(String upnpResponsePort) {
this.upnpresponseport = upnpResponsePort;
}
public String getUpnpDeviceDb() {
return upnpdevicedb;
}
public void setUpnpDeviceDb(String upnpDeviceDb) {
this.upnpdevicedb = upnpDeviceDb;
}
public IpList getVeraAddress() {
return veraaddress;
}
public void setVeraAddress(IpList veraAddress) {
this.veraaddress = veraAddress;
}
public IpList getHarmonyAddress() {
return harmonyaddress;
}
public void setHarmonyAddress(IpList harmonyaddress) {
this.harmonyaddress = harmonyaddress;
}
public String getHarmonyUser() {
return harmonyuser;
}
public void setHarmonyUser(String harmonyuser) {
this.harmonyuser = harmonyuser;
}
public String getHarmonyPwd() {
return harmonypwd;
}
public void setHarmonyPwd(String harmonypwd) {
this.harmonypwd = harmonypwd;
}
public boolean isUpnpStrict() {
return upnpstrict;
}
public void setUpnpStrict(boolean upnpStrict) {
this.upnpstrict = upnpStrict;
}
public boolean isTraceupnp() {
return traceupnp;
}
public void setTraceupnp(boolean traceupnp) {
this.traceupnp = traceupnp;
}
public boolean isDevMode() {
return devmode;
}
public void setDevMode(boolean devmode) {
this.devmode = devmode;
}
public String getNestuser() {
return nestuser;
}
public void setNestuser(String nestuser) {
this.nestuser = nestuser;
}
public String getNestpwd() {
return nestpwd;
}
public void setNestpwd(String nestpwd) {
this.nestpwd = nestpwd;
}
public boolean isVeraconfigured() {
return veraconfigured;
}
public void setVeraconfigured(boolean veraconfigured) {
this.veraconfigured = veraconfigured;
}
public boolean isHarmonyconfigured() {
return harmonyconfigured;
}
public void setHarmonyconfigured(boolean harmonyconfigured) {
this.harmonyconfigured = harmonyconfigured;
}
public boolean isNestConfigured() {
return nestconfigured;
}
public void setNestConfigured(boolean isNestConfigured) {
this.nestconfigured = isNestConfigured;
}
public Integer getButtonsleep() {
return buttonsleep;
}
public void setButtonsleep(Integer buttonsleep) {
this.buttonsleep = buttonsleep;
}
public String getConfigfile() {
return configfile;
}
public void setConfigfile(String configfile) {
this.configfile = configfile;
}
public Boolean isValidVera() {
if(this.getVeraAddress() == null)
return false;
List<NamedIP> devicesList = this.getVeraAddress().getDevices();
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
return false;
return true;
}
public Boolean isValidHarmony() {
if(this.getHarmonyAddress() == null)
return false;
List<NamedIP> devicesList = this.getHarmonyAddress().getDevices();
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
return false;
if(this.getHarmonyPwd() == null || this.getHarmonyPwd() == "")
return false;
if(this.getHarmonyUser() == null || this.getHarmonyUser() == "")
return false;
return true;
}
public Boolean isValidNest() {
if(this.getNestpwd() == null || this.getNestpwd() == "")
return false;
if(this.getNestuser() == null || this.getNestuser() == "")
return false;
return true;
}
}

View File

@@ -7,9 +7,6 @@ public class Configuration {
public final static String DEFAULT_ADDRESS = "1.1.1.1";
public final static String LOOP_BACK_ADDRESS = "127.0.0.1";
public final static String LOOP_BACK_INTERFACE = "lo";
public final static String DEFAULT_HARMONY_ADDRESS_LIST = "{devices:[{name:default,ip:1.1.1.1}]}";
public final static String DEFAULT_USER = "";
public final static String DEFAULT_PWD = "";
public final static String DFAULT_WEB_PORT = "8080";
public final static String DFAULT_BUTTON_SLEEP = "100";
public static final int UPNP_DISCOVERY_PORT = 1900;

View File

@@ -37,6 +37,7 @@ public class HABridge {
HueMulator theHueMulator;
UpnpSettingsResource theSettingResponder;
UpnpListener theUpnpListener;
SystemControl theSystem;
BridgeSettings bridgeSettings;
Version theVersion;
@@ -45,7 +46,7 @@ public class HABridge {
log.info("HA Bridge (v" + theVersion.getVersion() + ") starting....");
bridgeSettings = new BridgeSettings();
bridgeSettings.setRestart(false);
bridgeSettings.setReinit(false);
bridgeSettings.setStop(false);
while(!bridgeSettings.isStop()) {
bridgeSettings.buildSettings();
@@ -56,17 +57,20 @@ public class HABridge {
port(Integer.valueOf(bridgeSettings.getServerPort()));
// sparkjava config directive to set html static file location for Jetty
staticFileLocation("/public");
// setup system control api first
theSystem = new SystemControl(bridgeSettings, theVersion);
theSystem.setupServer();
//setup the harmony connection if available
harmonyHome = new HarmonyHome(bridgeSettings);
harmonyHome = new HarmonyHome(bridgeSettings.getBridgeSettingsDescriptor());
//setup the nest connection if available
nestHome = new NestHome(bridgeSettings);
nestHome = new NestHome(bridgeSettings.getBridgeSettingsDescriptor());
// setup the class to handle the resource setup rest api
theResources = new DeviceResource(bridgeSettings, theVersion, harmonyHome, nestHome);
theResources = new DeviceResource(bridgeSettings.getBridgeSettingsDescriptor(), harmonyHome, nestHome);
// setup the class to handle the hue emulator rest api
theHueMulator = new HueMulator(bridgeSettings, theResources.getDeviceRepository(), harmonyHome, nestHome);
theHueMulator = new HueMulator(bridgeSettings.getBridgeSettingsDescriptor(), theResources.getDeviceRepository(), harmonyHome, nestHome);
theHueMulator.setupServer();
// setup the class to handle the upnp response rest api
theSettingResponder = new UpnpSettingsResource(bridgeSettings);
theSettingResponder = new UpnpSettingsResource(bridgeSettings.getBridgeSettingsDescriptor());
theSettingResponder.setupServer();
// wait for the sparkjava initialization of the rest api classes to be complete
awaitInitialization();
@@ -76,7 +80,7 @@ public class HABridge {
if(theUpnpListener.startListening())
log.info("HA Bridge (v" + theVersion.getVersion() + ") reinitialization requessted....");
bridgeSettings.setRestart(false);
bridgeSettings.setReinit(false);
stop();
}
log.info("HA Bridge (v" + theVersion.getVersion() + ") exiting....");

View File

@@ -0,0 +1,173 @@
package com.bwssystems.HABridge;
import static spark.Spark.get;
import static spark.Spark.options;
import static spark.Spark.post;
import static spark.Spark.put;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import org.apache.http.HttpStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.dao.BackupFilename;
import com.google.gson.Gson;
public class SystemControl {
private static final Logger log = LoggerFactory.getLogger(SystemControl.class);
private static final String SYSTEM_CONTEXT = "/system";
private BridgeSettings bridgeSettings;
private Version version;
public SystemControl(BridgeSettings theBridgeSettings, Version theVersion) {
this.bridgeSettings = theBridgeSettings;
this.version = theVersion;
}
// This function sets up the sparkjava rest calls for the hue api
public void setupServer() {
log.info("Hue emulator service started....");
// http://ip_address:port/system/habridge/version gets the version of this bridge instance
get (SYSTEM_CONTEXT + "/habridge/version", "application/json", (request, response) -> {
log.debug("Get HA Bridge version: v" + version.getVersion());
response.status(HttpStatus.SC_OK);
return "{\"version\":\"" + version.getVersion() + "\"}";
});
// http://ip_address:port/system/settings which returns the bridge configuration settings
get(SYSTEM_CONTEXT + "/settings", "application/json", (request, response) -> {
log.debug("bridge settings requested from " + request.ip());
response.status(200);
return bridgeSettings;
}, new JsonTransformer());
// http://ip_address:port/system/control/reinit CORS request
options(SYSTEM_CONTEXT + "/control/reinit", "application/json", (request, response) -> {
response.status(HttpStatus.SC_OK);
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
response.header("Content-Type", "text/html; charset=utf-8");
return "";
});
// http://ip_address:port/system/control/reinit sets the parameter reinit the server
put(SYSTEM_CONTEXT + "/control/reinit", "application/json", (request, response) -> {
return reinit();
});
// http://ip_address:port/system/control/stop CORS request
options(SYSTEM_CONTEXT + "/control/stop", "application/json", (request, response) -> {
response.status(HttpStatus.SC_OK);
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
response.header("Content-Type", "text/html; charset=utf-8");
return "";
});
// http://ip_address:port/system/control/stop sets the parameter stop the server
put(SYSTEM_CONTEXT + "/control/stop", "application/json", (request, response) -> {
return stop();
});
// http://ip_address:port/system/backup/available returns a list of config backup filenames
get (SYSTEM_CONTEXT + "/backup/available", "application/json", (request, response) -> {
log.debug("Get backup filenames");
response.status(HttpStatus.SC_OK);
return bridgeSettings.getBackups();
}, new JsonTransformer());
// http://ip_address:port/system/backup/create CORS request
options(SYSTEM_CONTEXT + "/backup/create", "application/json", (request, response) -> {
response.status(HttpStatus.SC_OK);
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
response.header("Access-Control-Allow-Methods", "PUT");
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
response.header("Content-Type", "text/html; charset=utf-8");
return "";
});
put (SYSTEM_CONTEXT + "/backup/create", "application/json", (request, response) -> {
log.debug("Create backup: " + request.body());
BackupFilename aFilename = new Gson().fromJson(request.body(), BackupFilename.class);
BackupFilename returnFilename = new BackupFilename();
returnFilename.setFilename(bridgeSettings.backup(aFilename.getFilename()));
return returnFilename;
}, new JsonTransformer());
// http://ip_address:port/system/backup/delete CORS request
options(SYSTEM_CONTEXT + "/backup/delete", "application/json", (request, response) -> {
response.status(HttpStatus.SC_OK);
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
response.header("Access-Control-Allow-Methods", "POST");
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
response.header("Content-Type", "text/html; charset=utf-8");
return "";
});
post (SYSTEM_CONTEXT + "/backup/delete", "application/json", (request, response) -> {
log.debug("Delete backup: " + request.body());
BackupFilename aFilename = new Gson().fromJson(request.body(), BackupFilename.class);
if(aFilename != null)
bridgeSettings.deleteBackup(aFilename.getFilename());
else
log.warn("No filename given for delete backup.");
return null;
}, new JsonTransformer());
// http://ip_address:port/system/backup/restore CORS request
options(SYSTEM_CONTEXT + "/backup/restore", "application/json", (request, response) -> {
response.status(HttpStatus.SC_OK);
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
response.header("Access-Control-Allow-Methods", "POST");
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
response.header("Content-Type", "text/html; charset=utf-8");
return "";
});
post (SYSTEM_CONTEXT + "/backup/restore", "application/json", (request, response) -> {
log.debug("Restore backup: " + request.body());
BackupFilename aFilename = new Gson().fromJson(request.body(), BackupFilename.class);
if(aFilename != null) {
bridgeSettings.restoreBackup(aFilename.getFilename());
bridgeSettings.loadConfig();
}
else
log.warn("No filename given for restore backup.");
return null;
}, new JsonTransformer());
}
protected void pingListener() {
try {
byte[] buf = new byte[256];
String testData = "M-SEARCH * HTTP/1.1\nHOST: " + Configuration.UPNP_MULTICAST_ADDRESS + ":" + Configuration.UPNP_DISCOVERY_PORT + "ST: urn:schemas-upnp-org:device:CloudProxy:1\nMAN: \"ssdp:discover\"\nMX: 3";
buf = testData.getBytes();
MulticastSocket socket = new MulticastSocket(Configuration.UPNP_DISCOVERY_PORT);
InetAddress group = InetAddress.getByName(Configuration.UPNP_MULTICAST_ADDRESS);
DatagramPacket packet;
packet = new DatagramPacket(buf, buf.length, group, Configuration.UPNP_DISCOVERY_PORT);
socket.send(packet);
socket.close();
}
catch (IOException e) {
log.warn("Error pinging listener.", e);
}
}
public String reinit() {
bridgeSettings.setReinit(true);
pingListener();
return "{\"control\":\"reiniting\"}";
}
public String stop() {
bridgeSettings.setStop(true);
pingListener();
return "{\"control\":\"stopping\"}";
}
}

View File

@@ -3,23 +3,19 @@ package com.bwssystems.HABridge.dao;
import java.io.IOException;
import java.io.StringReader;
import java.nio.file.DirectoryStream;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.BackupHandler;
import com.bwssystems.HABridge.JsonTransformer;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.google.gson.stream.JsonReader;
@@ -30,7 +26,7 @@ import java.util.ListIterator;
* This is an in memory list to manage the configured devices and saves the list as a JSON string to a file for later
* loading.
*/
public class DeviceRepository {
public class DeviceRepository extends BackupHandler {
Map<String, DeviceDescriptor> devices;
Path repositoryPath;
final Random random = new Random();
@@ -38,14 +34,16 @@ public class DeviceRepository {
public DeviceRepository(String deviceDb) {
super();
_loadRepository(deviceDb);
repositoryPath = null;
repositoryPath = Paths.get(deviceDb);
setupParams(repositoryPath, ".bk", "device.db-");
_loadRepository(repositoryPath);
}
private void _loadRepository(String aFilePath){
repositoryPath = Paths.get(aFilePath);
_loadRepository(repositoryPath);
public void loadRepository() {
if(repositoryPath != null)
_loadRepository(repositoryPath);
}
private void _loadRepository(Path aPath){
String jsonContent = repositoryReader(aPath);
devices = new HashMap<String, DeviceDescriptor>();
@@ -93,66 +91,6 @@ public class DeviceRepository {
log.debug("Save device: " + aDescriptor.getName());
}
public String backup(String aFilename) {
if(aFilename == null || aFilename.equalsIgnoreCase("")) {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
aFilename = "devicedb-" + dateFormat.format(Calendar.getInstance().getTime()) + ".bk";
}
else
aFilename = aFilename + ".bk";
try {
Files.copy(repositoryPath, FileSystems.getDefault().getPath(repositoryPath.getParent().toString(), aFilename), StandardCopyOption.COPY_ATTRIBUTES);
} catch (IOException e) {
log.error("Could not backup to file: " + aFilename + " message: " + e.getMessage(), e);
}
log.debug("Backup repository: " + aFilename);
return aFilename;
}
public String deleteBackup(String aFilename) {
log.debug("Delete backup repository: " + aFilename);
try {
Files.delete(FileSystems.getDefault().getPath(repositoryPath.getParent().toString(), aFilename));
} catch (IOException e) {
log.error("Could not delete file: " + aFilename + " message: " + e.getMessage(), e);
}
return aFilename;
}
public String restoreBackup(String aFilename) {
log.debug("Restore backup repository: " + aFilename);
try {
Path target = null;
if(Files.exists(repositoryPath)) {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
target = FileSystems.getDefault().getPath(repositoryPath.getParent().toString(), "devicedb-" + dateFormat.format(Calendar.getInstance().getTime()) + ".bk");
Files.move(repositoryPath, target);
}
Files.copy(FileSystems.getDefault().getPath(repositoryPath.getParent().toString(), aFilename), repositoryPath, StandardCopyOption.COPY_ATTRIBUTES);
} catch (IOException e) {
log.error("Error restoring the file: " + aFilename + " message: " + e.getMessage(), e);
return null;
}
_loadRepository(repositoryPath);
return aFilename;
}
public List<String> getBackups() {
List<String> theFilenames = new ArrayList<String>();
Path dir = repositoryPath.getParent();
try (DirectoryStream<Path> stream =
Files.newDirectoryStream(dir, "*.{bk}")) {
for (Path entry: stream) {
theFilenames.add(entry.getFileName().toString());
}
} catch (IOException x) {
// IOException can never be thrown by the iteration.
// In this snippet, it can // only be thrown by newDirectoryStream.
log.error("Issue getting direcotyr listing for backups - " + x.getMessage());
}
return theFilenames;
}
public String delete(DeviceDescriptor aDescriptor) {
if (aDescriptor != null) {
devices.remove(aDescriptor.getId());

View File

@@ -16,8 +16,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.BridgeSettings;
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
import com.bwssystems.HABridge.JsonTransformer;
import com.bwssystems.HABridge.Version;
import com.bwssystems.HABridge.dao.BackupFilename;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.dao.DeviceRepository;
@@ -35,12 +35,11 @@ public class DeviceResource {
private DeviceRepository deviceRepository;
private VeraHome veraHome;
private Version version;
private HarmonyHome myHarmonyHome;
private NestHome nestHome;
private static final Set<String> supportedVerbs = new HashSet<>(Arrays.asList("get", "put", "post"));
public DeviceResource(BridgeSettings theSettings, Version theVersion, HarmonyHome theHarmonyHome, NestHome aNestHome) {
public DeviceResource(BridgeSettingsDescriptor theSettings, HarmonyHome theHarmonyHome, NestHome aNestHome) {
this.deviceRepository = new DeviceRepository(theSettings.getUpnpDeviceDb());
if(theSettings.isValidVera())
@@ -58,7 +57,6 @@ public class DeviceResource {
else
this.nestHome = null;
this.version = theVersion;
setupEndpoints();
}
@@ -172,12 +170,6 @@ public class DeviceResource {
return null;
}, new JsonTransformer());
get (API_CONTEXT + "/habridge/version", "application/json", (request, response) -> {
log.debug("Get HA Bridge version: v" + version.getVersion());
response.status(HttpStatus.SC_OK);
return "{\"version\":\"" + version.getVersion() + "\"}";
});
get (API_CONTEXT + "/vera/devices", "application/json", (request, response) -> {
log.debug("Get vera devices");
if(veraHome == null){
@@ -293,8 +285,10 @@ public class DeviceResource {
post (API_CONTEXT + "/backup/restore", "application/json", (request, response) -> {
log.debug("Restore backup: " + request.body());
BackupFilename aFilename = new Gson().fromJson(request.body(), BackupFilename.class);
if(aFilename != null)
if(aFilename != null) {
deviceRepository.restoreBackup(aFilename.getFilename());
deviceRepository.loadRepository();
}
else
log.warn("No filename given for restore backup.");
return null;

View File

@@ -1,7 +1,6 @@
package com.bwssystems.HABridge.hue;
import com.bwssystems.HABridge.BridgeSettings;
import com.bwssystems.HABridge.Configuration;
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
import com.bwssystems.HABridge.JsonTransformer;
import com.bwssystems.HABridge.api.UserCreateRequest;
import com.bwssystems.HABridge.api.hue.DeviceResponse;
@@ -46,7 +45,6 @@ import java.math.BigDecimal;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -71,11 +69,11 @@ public class HueMulator {
private Nest theNest;
private HttpClient httpClient;
private ObjectMapper mapper;
private BridgeSettings bridgeSettings;
private BridgeSettingsDescriptor bridgeSettings;
private byte[] sendData;
public HueMulator(BridgeSettings theBridgeSettings, DeviceRepository aDeviceRepository, HarmonyHome theHarmonyHome, NestHome aNestHome){
public HueMulator(BridgeSettingsDescriptor theBridgeSettings, DeviceRepository aDeviceRepository, HarmonyHome theHarmonyHome, NestHome aNestHome){
httpClient = HttpClients.createDefault();
mapper = new ObjectMapper(); //armzilla: work around Echo incorrect content type and breaking mapping. Map manually
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
@@ -441,38 +439,6 @@ public class HueMulator {
return responseString;
});
// http://ip_address:port/api/control/restart CORS request
options(HUE_CONTEXT + "/control/restart", "application/json", (request, response) -> {
response.status(HttpStatus.SC_OK);
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
response.header("Content-Type", "text/html; charset=utf-8");
return "";
});
// http://ip_address:port/api//control/restart sets the parameter restart the server
put(HUE_CONTEXT + "/control/restart", "application/json", (request, response) -> {
bridgeSettings.setRestart(true);
pingListener();
return "{\"control\":\"restarting\"}";
});
// http://ip_address:port/api/control/stop CORS request
options(HUE_CONTEXT + "/control/stop", "application/json", (request, response) -> {
response.status(HttpStatus.SC_OK);
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
response.header("Access-Control-Allow-Methods", "GET, POST, PUT");
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
response.header("Content-Type", "text/html; charset=utf-8");
return "";
});
// http://ip_address:port/api//control/stop sets the parameter stop the server
put(HUE_CONTEXT + "/control/stop", "application/json", (request, response) -> {
bridgeSettings.setStop(true);
pingListener();
return "{\"control\":\"stopping\"}";
});
}
/* light weight templating here, was going to use free marker but it was a bit too
@@ -544,23 +510,4 @@ public class HueMulator {
}
return false;
}
protected void pingListener() {
try {
byte[] buf = new byte[256];
String testData = "M-SEARCH * HTTP/1.1\nHOST: " + Configuration.UPNP_MULTICAST_ADDRESS + ":" + Configuration.UPNP_DISCOVERY_PORT + "ST: urn:schemas-upnp-org:device:CloudProxy:1\nMAN: \"ssdp:discover\"\nMX: 3";
buf = testData.getBytes();
MulticastSocket socket = new MulticastSocket(Configuration.UPNP_DISCOVERY_PORT);
InetAddress group = InetAddress.getByName(Configuration.UPNP_MULTICAST_ADDRESS);
DatagramPacket packet;
packet = new DatagramPacket(buf, buf.length, group, Configuration.UPNP_DISCOVERY_PORT);
socket.send(packet);
socket.close();
}
catch (IOException e) {
log.warn("Error pinging listener.", e);
}
}
}

View File

@@ -80,21 +80,27 @@ public class UpnpListener {
if(isSSDPDiscovery(packet)){
sendUpnpResponse(responseSocket, packet.getAddress(), packet.getPort());
}
if(bridgeSettings.isRestart() || bridgeSettings.isStop())
if(bridgeSettings.isReinit() || bridgeSettings.isStop()) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// noop
}
loopControl = false;
}
}
upnpMulticastSocket.close();
responseSocket.close();
} catch (IOException e) {
log.error("UpnpListener encountered an error opening sockets. Shutting down", e);
}
if(bridgeSettings.isRestart())
if(bridgeSettings.isReinit())
log.info("UPNP Discovery Listener - ended, restart found");
if(bridgeSettings.isStop())
log.info("UPNP Discovery Listener - ended, stop found");
if(!bridgeSettings.isStop()&& !bridgeSettings.isRestart())
if(!bridgeSettings.isStop()&& !bridgeSettings.isReinit())
log.info("UPNP Discovery Listener - ended, error found");
return bridgeSettings.isRestart();
return bridgeSettings.isReinit();
}
/**

View File

@@ -3,8 +3,7 @@ package com.bwssystems.HABridge.upnp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.BridgeSettings;
import com.bwssystems.HABridge.JsonTransformer;
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
import static spark.Spark.get;
@@ -12,11 +11,9 @@ import static spark.Spark.get;
*
*/
public class UpnpSettingsResource {
private static final String UPNP_CONTEXT = "/upnp";
private Logger log = LoggerFactory.getLogger(UpnpSettingsResource.class);
private BridgeSettings theSettings;
private BridgeSettingsDescriptor theSettings;
private String hueTemplate = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" + "<root xmlns=\"urn:schemas-upnp-org:device-1-0\">\n"
+ "<specVersion>\n" + "<major>1</major>\n" + "<minor>0</minor>\n" + "</specVersion>\n"
@@ -40,22 +37,9 @@ public class UpnpSettingsResource {
+ "<depth>24</depth>\n" + "<url>hue_logo_3.png</url>\n" + "</icon>\n" + "</iconList>\n" + "</device>\n"
+ "</root>\n";
public UpnpSettingsResource(BridgeSettings theBridgeSettings) {
public UpnpSettingsResource(BridgeSettingsDescriptor theBridgeSettings) {
super();
this.theSettings = new BridgeSettings();
this.theSettings.setDevMode(theBridgeSettings.isDevMode());
this.theSettings.setHarmonyAddress(theBridgeSettings.getHarmonyAddress());
this.theSettings.setServerPort(theBridgeSettings.getServerPort());
this.theSettings.setTraceupnp(theBridgeSettings.isTraceupnp());
this.theSettings.setUpnpConfigAddress(theBridgeSettings.getUpnpConfigAddress());
this.theSettings.setUpnpDeviceDb(theBridgeSettings.getUpnpDeviceDb());
this.theSettings.setButtonsleep(theBridgeSettings.getButtonsleep());
this.theSettings.setUpnpResponsePort(theBridgeSettings.getUpnpResponsePort());
this.theSettings.setUpnpStrict(theBridgeSettings.isUpnpStrict());
this.theSettings.setVeraAddress(theBridgeSettings.getVeraAddress());
this.theSettings.setVeraconfigured(theBridgeSettings.isValidVera());
this.theSettings.setHarmonyconfigured(theBridgeSettings.isValidHarmony());
this.theSettings.setNestConfigured(theBridgeSettings.isValidNest());
this.theSettings = theBridgeSettings;
}
public void setupServer() {
@@ -88,14 +72,5 @@ public class UpnpSettingsResource {
return filledTemplate;
} );
// http://ip_address:port/upnp/settings which returns the bridge configuration settings
get(UPNP_CONTEXT + "/settings", "application/json", (request, response) -> {
log.debug("bridge settings requested from " + request.ip());
response.status(200);
return theSettings;
}, new JsonTransformer());
}
}

View File

@@ -8,7 +8,7 @@ import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.BridgeSettings;
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
import com.bwssystems.nest.controller.Home;
import com.bwssystems.nest.controller.Nest;
import com.bwssystems.nest.controller.NestSession;
@@ -23,7 +23,7 @@ public class NestHome {
private Nest theNest;
private ArrayList<NestItem> nestItems;
public NestHome(BridgeSettings bridgeSettings) {
public NestHome(BridgeSettingsDescriptor bridgeSettings) {
theSession = null;
theNest = null;
nestItems = null;

View File

@@ -11,6 +11,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.BridgeSettings;
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
import com.bwssystems.HABridge.IpList;
import com.bwssystems.HABridge.NamedIP;
@@ -21,7 +22,7 @@ public class HarmonyHome {
private static final Logger log = LoggerFactory.getLogger(HarmonyHome.class);
private Map<String, HarmonyServer> hubs;
public HarmonyHome(BridgeSettings bridgeSettings) {
public HarmonyHome(BridgeSettingsDescriptor bridgeSettings) {
super();
hubs = new HashMap<String, HarmonyServer>();
if(!bridgeSettings.isValidHarmony() && !bridgeSettings.isDevMode())

View File

@@ -7,7 +7,7 @@ import javax.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.BridgeSettings;
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
import com.bwssystems.HABridge.NamedIP;
import com.google.inject.Guice;
import com.google.inject.Injector;
@@ -36,7 +36,7 @@ public class HarmonyServer {
myNameAndIP = theHarmonyAddress;
}
public static HarmonyServer setup(BridgeSettings bridgeSettings, NamedIP theHarmonyAddress) throws Exception {
public static HarmonyServer setup(BridgeSettingsDescriptor bridgeSettings, NamedIP theHarmonyAddress) throws Exception {
if(!bridgeSettings.isValidHarmony() && !bridgeSettings.isDevMode()) {
return new HarmonyServer(theHarmonyAddress);
}
@@ -50,7 +50,7 @@ public class HarmonyServer {
return mainObject;
}
private void execute(BridgeSettings mySettings) throws Exception {
private void execute(BridgeSettingsDescriptor mySettings) throws Exception {
Boolean noopCalls = Boolean.parseBoolean(System.getProperty("noop.calls", "false"));
String modeString = "";
if(dummyProvider != null)

View File

@@ -9,7 +9,7 @@ import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.BridgeSettings;
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
import com.bwssystems.HABridge.NamedIP;
import com.bwssystems.luupRequests.Device;
import com.bwssystems.luupRequests.Scene;
@@ -18,7 +18,7 @@ public class VeraHome {
private static final Logger log = LoggerFactory.getLogger(VeraHome.class);
private Map<String, VeraInfo> veras;
public VeraHome(BridgeSettings bridgeSettings) {
public VeraHome(BridgeSettingsDescriptor bridgeSettings) {
veras = new HashMap<String, VeraInfo>();
if(!bridgeSettings.isValidVera())
return;