mirror of
https://github.com/bwssytems/ha-bridge.git
synced 2025-12-19 00:20:26 +00:00
Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c773477a43 | ||
|
|
5d1f0ce3b6 | ||
|
|
7e0fd6c21b | ||
|
|
3bf52f5da0 | ||
|
|
bd856d8f9e | ||
|
|
73b2be752e | ||
|
|
dda7a7a34a | ||
|
|
f238e05533 | ||
|
|
aaaebd0c05 | ||
|
|
9a1924422e | ||
|
|
e446c618ce | ||
|
|
60d35acff9 | ||
|
|
c9adab53a9 | ||
|
|
72b6b2027b | ||
|
|
60239bad82 | ||
|
|
aecd589308 | ||
|
|
ee45cee8e3 | ||
|
|
21e5dfb338 | ||
|
|
b73a4cd666 | ||
|
|
05418fdda1 | ||
|
|
a717fd7c68 | ||
|
|
8408d7350e | ||
|
|
3ba8f56db2 | ||
|
|
7a0946e3b7 | ||
|
|
50c9369d71 | ||
|
|
6c2a34f507 | ||
|
|
ee2c105040 | ||
|
|
3ac83912f3 | ||
|
|
e62fcf7765 |
2
pom.xml
2
pom.xml
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
<groupId>com.bwssystems.HABridge</groupId>
|
<groupId>com.bwssystems.HABridge</groupId>
|
||||||
<artifactId>ha-bridge</artifactId>
|
<artifactId>ha-bridge</artifactId>
|
||||||
<version>1.4.2</version>
|
<version>2.0.4</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>HA Bridge</name>
|
<name>HA Bridge</name>
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ public class BridgeSettings extends BackupHandler {
|
|||||||
if(Files.exists(filePath) && Files.isReadable(filePath))
|
if(Files.exists(filePath) && Files.isReadable(filePath))
|
||||||
configFileProperty = Configuration.CONFIG_FILE;
|
configFileProperty = Configuration.CONFIG_FILE;
|
||||||
}
|
}
|
||||||
|
String serverPortOverride = System.getProperty("server.port");
|
||||||
if(configFileProperty != null)
|
if(configFileProperty != null)
|
||||||
{
|
{
|
||||||
log.info("reading from config file: " + configFileProperty);
|
log.info("reading from config file: " + configFileProperty);
|
||||||
@@ -154,6 +154,9 @@ public class BridgeSettings extends BackupHandler {
|
|||||||
theBridgeSettings.setVeraconfigured(theBridgeSettings.isValidVera());
|
theBridgeSettings.setVeraconfigured(theBridgeSettings.isValidVera());
|
||||||
theBridgeSettings.setHarmonyconfigured(theBridgeSettings.isValidHarmony());
|
theBridgeSettings.setHarmonyconfigured(theBridgeSettings.isValidHarmony());
|
||||||
theBridgeSettings.setNestConfigured(theBridgeSettings.isValidNest());
|
theBridgeSettings.setNestConfigured(theBridgeSettings.isValidNest());
|
||||||
|
theBridgeSettings.setHueconfigured(theBridgeSettings.isValidHue());
|
||||||
|
if(serverPortOverride != null)
|
||||||
|
theBridgeSettings.setServerPort(serverPortOverride);
|
||||||
setupParams(Paths.get(theBridgeSettings.getConfigfile()), ".cfgbk", "habridge.config-");
|
setupParams(Paths.get(theBridgeSettings.getConfigfile()), ".cfgbk", "habridge.config-");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,6 +190,8 @@ public class BridgeSettings extends BackupHandler {
|
|||||||
theBridgeSettings.setNestConfigured(aBridgeSettings.isValidNest());
|
theBridgeSettings.setNestConfigured(aBridgeSettings.isValidNest());
|
||||||
theBridgeSettings.setNumberoflogmessages(aBridgeSettings.getNumberoflogmessages());
|
theBridgeSettings.setNumberoflogmessages(aBridgeSettings.getNumberoflogmessages());
|
||||||
theBridgeSettings.setFarenheit(aBridgeSettings.isFarenheit());
|
theBridgeSettings.setFarenheit(aBridgeSettings.isFarenheit());
|
||||||
|
theBridgeSettings.setHueaddress(aBridgeSettings.getHueaddress());
|
||||||
|
theBridgeSettings.setHueconfigured(aBridgeSettings.isValidHue());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void save(BridgeSettingsDescriptor newBridgeSettings) {
|
public void save(BridgeSettingsDescriptor newBridgeSettings) {
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ public class BridgeSettingsDescriptor {
|
|||||||
private boolean farenheit;
|
private boolean farenheit;
|
||||||
private String configfile;
|
private String configfile;
|
||||||
private Integer numberoflogmessages;
|
private Integer numberoflogmessages;
|
||||||
|
private IpList hueaddress;
|
||||||
|
private boolean hueconfigured;
|
||||||
|
|
||||||
public BridgeSettingsDescriptor() {
|
public BridgeSettingsDescriptor() {
|
||||||
super();
|
super();
|
||||||
@@ -30,6 +32,7 @@ public class BridgeSettingsDescriptor {
|
|||||||
this.nestconfigured = false;
|
this.nestconfigured = false;
|
||||||
this.veraconfigured = false;
|
this.veraconfigured = false;
|
||||||
this.harmonyconfigured = false;
|
this.harmonyconfigured = false;
|
||||||
|
this.hueconfigured = false;
|
||||||
this.farenheit = true;
|
this.farenheit = true;
|
||||||
}
|
}
|
||||||
public String getUpnpConfigAddress() {
|
public String getUpnpConfigAddress() {
|
||||||
@@ -152,6 +155,18 @@ public class BridgeSettingsDescriptor {
|
|||||||
public void setFarenheit(boolean farenheit) {
|
public void setFarenheit(boolean farenheit) {
|
||||||
this.farenheit = farenheit;
|
this.farenheit = farenheit;
|
||||||
}
|
}
|
||||||
|
public IpList getHueaddress() {
|
||||||
|
return hueaddress;
|
||||||
|
}
|
||||||
|
public void setHueaddress(IpList hueaddress) {
|
||||||
|
this.hueaddress = hueaddress;
|
||||||
|
}
|
||||||
|
public boolean isHueconfigured() {
|
||||||
|
return hueconfigured;
|
||||||
|
}
|
||||||
|
public void setHueconfigured(boolean hueconfigured) {
|
||||||
|
this.hueconfigured = hueconfigured;
|
||||||
|
}
|
||||||
public Boolean isValidVera() {
|
public Boolean isValidVera() {
|
||||||
if(this.getVeraAddress() == null || this.getVeraAddress().getDevices().size() <= 0)
|
if(this.getVeraAddress() == null || this.getVeraAddress().getDevices().size() <= 0)
|
||||||
return false;
|
return false;
|
||||||
@@ -179,5 +194,12 @@ public class BridgeSettingsDescriptor {
|
|||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
public Boolean isValidHue() {
|
||||||
|
if(this.getHueaddress() == null || this.getHueaddress().getDevices().size() <= 0)
|
||||||
|
return false;
|
||||||
|
List<NamedIP> devicesList = this.getHueaddress().getDevices();
|
||||||
|
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import com.bwssystems.HABridge.upnp.UpnpListener;
|
|||||||
import com.bwssystems.HABridge.upnp.UpnpSettingsResource;
|
import com.bwssystems.HABridge.upnp.UpnpSettingsResource;
|
||||||
import com.bwssystems.NestBridge.NestHome;
|
import com.bwssystems.NestBridge.NestHome;
|
||||||
import com.bwssystems.harmony.HarmonyHome;
|
import com.bwssystems.harmony.HarmonyHome;
|
||||||
|
import com.bwssystems.hue.HueHome;
|
||||||
|
|
||||||
public class HABridge {
|
public class HABridge {
|
||||||
|
|
||||||
@@ -34,6 +35,7 @@ public class HABridge {
|
|||||||
DeviceResource theResources;
|
DeviceResource theResources;
|
||||||
HarmonyHome harmonyHome;
|
HarmonyHome harmonyHome;
|
||||||
NestHome nestHome;
|
NestHome nestHome;
|
||||||
|
HueHome hueHome;
|
||||||
HueMulator theHueMulator;
|
HueMulator theHueMulator;
|
||||||
UpnpSettingsResource theSettingResponder;
|
UpnpSettingsResource theSettingResponder;
|
||||||
UpnpListener theUpnpListener;
|
UpnpListener theUpnpListener;
|
||||||
@@ -62,10 +64,12 @@ public class HABridge {
|
|||||||
harmonyHome = new HarmonyHome(bridgeSettings.getBridgeSettingsDescriptor());
|
harmonyHome = new HarmonyHome(bridgeSettings.getBridgeSettingsDescriptor());
|
||||||
//setup the nest connection if available
|
//setup the nest connection if available
|
||||||
nestHome = new NestHome(bridgeSettings.getBridgeSettingsDescriptor());
|
nestHome = new NestHome(bridgeSettings.getBridgeSettingsDescriptor());
|
||||||
|
//setup the hue passtrhu configuration if available
|
||||||
|
hueHome = new HueHome(bridgeSettings.getBridgeSettingsDescriptor());
|
||||||
// setup the class to handle the resource setup rest api
|
// setup the class to handle the resource setup rest api
|
||||||
theResources = new DeviceResource(bridgeSettings.getBridgeSettingsDescriptor(), harmonyHome, nestHome);
|
theResources = new DeviceResource(bridgeSettings.getBridgeSettingsDescriptor(), harmonyHome, nestHome, hueHome);
|
||||||
// setup the class to handle the hue emulator rest api
|
// setup the class to handle the hue emulator rest api
|
||||||
theHueMulator = new HueMulator(bridgeSettings.getBridgeSettingsDescriptor(), theResources.getDeviceRepository(), harmonyHome, nestHome);
|
theHueMulator = new HueMulator(bridgeSettings.getBridgeSettingsDescriptor(), theResources.getDeviceRepository(), harmonyHome, nestHome, hueHome);
|
||||||
theHueMulator.setupServer();
|
theHueMulator.setupServer();
|
||||||
// setup the class to handle the upnp response rest api
|
// setup the class to handle the upnp response rest api
|
||||||
theSettingResponder = new UpnpSettingsResource(bridgeSettings.getBridgeSettingsDescriptor());
|
theSettingResponder = new UpnpSettingsResource(bridgeSettings.getBridgeSettingsDescriptor());
|
||||||
@@ -77,6 +81,8 @@ public class HABridge {
|
|||||||
theUpnpListener = new UpnpListener(bridgeSettings.getBridgeSettingsDescriptor(), bridgeSettings.getBridgeControl());
|
theUpnpListener = new UpnpListener(bridgeSettings.getBridgeSettingsDescriptor(), bridgeSettings.getBridgeControl());
|
||||||
if(theUpnpListener.startListening())
|
if(theUpnpListener.startListening())
|
||||||
log.info("HA Bridge (v" + theVersion.getVersion() + ") reinitialization requessted....");
|
log.info("HA Bridge (v" + theVersion.getVersion() + ") reinitialization requessted....");
|
||||||
|
else
|
||||||
|
bridgeSettings.getBridgeControl().setStop(true);
|
||||||
|
|
||||||
bridgeSettings.getBridgeControl().setReinit(false);
|
bridgeSettings.getBridgeControl().setReinit(false);
|
||||||
stop();
|
stop();
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import com.bwssystems.HABridge.dao.BackupFilename;
|
|||||||
import com.bwssystems.logservices.LoggerInfo;
|
import com.bwssystems.logservices.LoggerInfo;
|
||||||
import com.bwssystems.logservices.LoggingForm;
|
import com.bwssystems.logservices.LoggingForm;
|
||||||
import com.bwssystems.logservices.LoggingManager;
|
import com.bwssystems.logservices.LoggingManager;
|
||||||
import com.bwssystems.util.JsonFreeTextStringFormatter;
|
import com.bwssystems.util.TextStringFormatter;
|
||||||
import com.bwssystems.util.JsonTransformer;
|
import com.bwssystems.util.JsonTransformer;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ public class SystemControl {
|
|||||||
LoggingEvent le;
|
LoggingEvent le;
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
le = (LoggingEvent) cyclicBufferAppender.get(i);
|
le = (LoggingEvent) cyclicBufferAppender.get(i);
|
||||||
logMsgs = logMsgs + ( i > 0?",{":"{") + "\"time\":\"" + dateFormat.format(le.getTimeStamp()) + "\",\"level\":\"" + le.getLevel().levelStr + "\",\"component\":\"" + le.getLoggerName() + "\",\"message\":\"" + JsonFreeTextStringFormatter.forJSON(le.getFormattedMessage()) + "\"}";
|
logMsgs = logMsgs + ( i > 0?",{":"{") + "\"time\":\"" + dateFormat.format(le.getTimeStamp()) + "\",\"level\":\"" + le.getLevel().levelStr + "\",\"component\":\"" + le.getLoggerName() + "\",\"message\":\"" + TextStringFormatter.forJSON(le.getFormattedMessage()) + "\"}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logMsgs = logMsgs + "]";
|
logMsgs = logMsgs + "]";
|
||||||
|
|||||||
13
src/main/java/com/bwssystems/HABridge/api/CallItem.java
Normal file
13
src/main/java/com/bwssystems/HABridge/api/CallItem.java
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package com.bwssystems.HABridge.api;
|
||||||
|
|
||||||
|
public class CallItem {
|
||||||
|
private String item;
|
||||||
|
|
||||||
|
public String getItem() {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setItem(String anitem) {
|
||||||
|
item = anitem;
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/main/java/com/bwssystems/HABridge/api/NameValue.java
Normal file
18
src/main/java/com/bwssystems/HABridge/api/NameValue.java
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package com.bwssystems.HABridge.api;
|
||||||
|
|
||||||
|
public class NameValue {
|
||||||
|
private String name;
|
||||||
|
private String value;
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
public void setValue(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.bwssystems.HABridge.api;
|
||||||
|
|
||||||
|
public class SuccessUserResponse {
|
||||||
|
private UserCreateResponse success;
|
||||||
|
|
||||||
|
public UserCreateResponse getSuccess() {
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSuccess(UserCreateResponse success) {
|
||||||
|
this.success = success;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.bwssystems.HABridge.api;
|
||||||
|
|
||||||
|
public class UserCreateResponse {
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -71,14 +71,8 @@ public class DeviceResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static DeviceResponse createResponse(DeviceDescriptor device){
|
public static DeviceResponse createResponse(DeviceDescriptor device){
|
||||||
DeviceState deviceState = new DeviceState();
|
|
||||||
DeviceResponse response = new DeviceResponse();
|
DeviceResponse response = new DeviceResponse();
|
||||||
response.setState(deviceState);
|
response.setState(device.getDeviceState());
|
||||||
deviceState.setOn(device.getDeviceState());
|
|
||||||
deviceState.setReachable(true);
|
|
||||||
deviceState.setEffect("none");
|
|
||||||
deviceState.setAlert("none");
|
|
||||||
deviceState.setBri(device.getDeviceSetValue());
|
|
||||||
|
|
||||||
response.setName(device.getName());
|
response.setName(device.getName());
|
||||||
response.setUniqueid(device.getId());
|
response.setUniqueid(device.getId());
|
||||||
|
|||||||
@@ -1,15 +1,22 @@
|
|||||||
package com.bwssystems.HABridge.api.hue;
|
package com.bwssystems.HABridge.api.hue;
|
||||||
|
|
||||||
|
// import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by arm on 4/14/15.
|
* Created by arm on 4/14/15.
|
||||||
*/
|
*/
|
||||||
public class DeviceState {
|
public class DeviceState {
|
||||||
private boolean on;
|
private boolean on;
|
||||||
private int bri = 0;
|
private int bri;
|
||||||
|
private int hue;
|
||||||
|
private int sat;
|
||||||
private String effect;
|
private String effect;
|
||||||
|
private int ct;
|
||||||
private String alert;
|
private String alert;
|
||||||
|
private String colormode;
|
||||||
private boolean reachable;
|
private boolean reachable;
|
||||||
|
private List<Double> xy;
|
||||||
|
|
||||||
public boolean isOn() {
|
public boolean isOn() {
|
||||||
return on;
|
return on;
|
||||||
@@ -27,6 +34,22 @@ public class DeviceState {
|
|||||||
this.bri = bri;
|
this.bri = bri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getHue() {
|
||||||
|
return hue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHue(int hue) {
|
||||||
|
this.hue = hue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSat() {
|
||||||
|
return sat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSat(int sat) {
|
||||||
|
this.sat = sat;
|
||||||
|
}
|
||||||
|
|
||||||
public String getEffect() {
|
public String getEffect() {
|
||||||
return effect;
|
return effect;
|
||||||
}
|
}
|
||||||
@@ -35,6 +58,14 @@ public class DeviceState {
|
|||||||
this.effect = effect;
|
this.effect = effect;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getCt() {
|
||||||
|
return ct;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCt(int ct) {
|
||||||
|
this.ct = ct;
|
||||||
|
}
|
||||||
|
|
||||||
public String getAlert() {
|
public String getAlert() {
|
||||||
return alert;
|
return alert;
|
||||||
}
|
}
|
||||||
@@ -43,6 +74,14 @@ public class DeviceState {
|
|||||||
this.alert = alert;
|
this.alert = alert;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getColormode() {
|
||||||
|
return colormode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColormode(String colormode) {
|
||||||
|
this.colormode = colormode;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isReachable() {
|
public boolean isReachable() {
|
||||||
return reachable;
|
return reachable;
|
||||||
}
|
}
|
||||||
@@ -51,6 +90,31 @@ public class DeviceState {
|
|||||||
this.reachable = reachable;
|
this.reachable = reachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Double> getXy() {
|
||||||
|
return xy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setXy(List<Double> xy) {
|
||||||
|
this.xy = xy;
|
||||||
|
}
|
||||||
|
public static DeviceState createDeviceState() {
|
||||||
|
DeviceState newDeviceState = new DeviceState();
|
||||||
|
newDeviceState.fillIn();
|
||||||
|
// newDeviceState.setColormode("none");
|
||||||
|
// ArrayList<Double> doubleArray = new ArrayList<Double>();
|
||||||
|
// doubleArray.add(new Double(0));
|
||||||
|
// doubleArray.add(new Double(0));
|
||||||
|
// newDeviceState.setXy(doubleArray);
|
||||||
|
|
||||||
|
return newDeviceState;
|
||||||
|
}
|
||||||
|
public void fillIn() {
|
||||||
|
if(this.getAlert() == null)
|
||||||
|
this.setAlert("none");
|
||||||
|
if(this.getEffect() == null)
|
||||||
|
this.setEffect("none");
|
||||||
|
this.setReachable(true);
|
||||||
|
}
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "DeviceState{" +
|
return "DeviceState{" +
|
||||||
|
|||||||
@@ -4,17 +4,18 @@ import java.util.HashMap;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.bwssystems.HABridge.api.hue.DeviceResponse;
|
import com.bwssystems.HABridge.api.hue.DeviceResponse;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by arm on 4/14/15.
|
* Created by arm on 4/14/15.
|
||||||
*/
|
*/
|
||||||
public class HueApiResponse {
|
public class HueApiResponse {
|
||||||
private Map<String, DeviceResponse> lights;
|
private Map<String, DeviceResponse> lights;
|
||||||
private Map<String, String> scenes;
|
private Map<String, JsonObject> scenes;
|
||||||
private Map<String, String> groups;
|
private Map<String, JsonObject> groups;
|
||||||
private Map<String, String> schedules;
|
private Map<String, JsonObject> schedules;
|
||||||
private Map<String, String> sensors;
|
private Map<String, JsonObject> sensors;
|
||||||
private Map<String, String> rules;
|
private Map<String, JsonObject> rules;
|
||||||
private HueConfig config;
|
private HueConfig config;
|
||||||
|
|
||||||
public HueApiResponse(String name, String ipaddress, String devicetype, String userid) {
|
public HueApiResponse(String name, String ipaddress, String devicetype, String userid) {
|
||||||
@@ -35,43 +36,43 @@ public class HueApiResponse {
|
|||||||
this.lights = lights;
|
this.lights = lights;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, String> getScenes() {
|
public Map<String, JsonObject> getScenes() {
|
||||||
return scenes;
|
return scenes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setScenes(Map<String, String> scenes) {
|
public void setScenes(Map<String, JsonObject> scenes) {
|
||||||
this.scenes = scenes;
|
this.scenes = scenes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, String> getGroups() {
|
public Map<String, JsonObject> getGroups() {
|
||||||
return groups;
|
return groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setGroups(Map<String, String> groups) {
|
public void setGroups(Map<String, JsonObject> groups) {
|
||||||
this.groups = groups;
|
this.groups = groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, String> getSchedules() {
|
public Map<String, JsonObject> getSchedules() {
|
||||||
return schedules;
|
return schedules;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSchedules(Map<String, String> schedules) {
|
public void setSchedules(Map<String, JsonObject> schedules) {
|
||||||
this.schedules = schedules;
|
this.schedules = schedules;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, String> getSensors() {
|
public Map<String, JsonObject> getSensors() {
|
||||||
return sensors;
|
return sensors;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSensors(Map<String, String> sensors) {
|
public void setSensors(Map<String, JsonObject> sensors) {
|
||||||
this.sensors = sensors;
|
this.sensors = sensors;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, String> getRules() {
|
public Map<String, JsonObject> getRules() {
|
||||||
return rules;
|
return rules;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRules(Map<String, String> rules) {
|
public void setRules(Map<String, JsonObject> rules) {
|
||||||
this.rules = rules;
|
this.rules = rules;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.bwssystems.HABridge.dao;
|
package com.bwssystems.HABridge.dao;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.api.hue.DeviceState;
|
||||||
import com.google.gson.annotations.Expose;
|
import com.google.gson.annotations.Expose;
|
||||||
import com.google.gson.annotations.SerializedName;
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
@@ -34,6 +35,9 @@ public class DeviceDescriptor{
|
|||||||
@SerializedName("onUrl")
|
@SerializedName("onUrl")
|
||||||
@Expose
|
@Expose
|
||||||
private String onUrl;
|
private String onUrl;
|
||||||
|
@SerializedName("headers")
|
||||||
|
@Expose
|
||||||
|
private String headers;
|
||||||
@SerializedName("httpVerb")
|
@SerializedName("httpVerb")
|
||||||
@Expose
|
@Expose
|
||||||
private String httpVerb;
|
private String httpVerb;
|
||||||
@@ -47,8 +51,7 @@ public class DeviceDescriptor{
|
|||||||
@Expose
|
@Expose
|
||||||
private String contentBodyOff;
|
private String contentBodyOff;
|
||||||
|
|
||||||
private boolean deviceState;
|
private DeviceState deviceState;
|
||||||
private int deviceSetValue;
|
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
@@ -122,6 +125,14 @@ public class DeviceDescriptor{
|
|||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getHeaders() {
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHeaders(String headers) {
|
||||||
|
this.headers = headers;
|
||||||
|
}
|
||||||
|
|
||||||
public String getHttpVerb() {
|
public String getHttpVerb() {
|
||||||
return httpVerb;
|
return httpVerb;
|
||||||
}
|
}
|
||||||
@@ -154,21 +165,14 @@ public class DeviceDescriptor{
|
|||||||
this.contentBodyOff = contentBodyOff;
|
this.contentBodyOff = contentBodyOff;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean getDeviceState() {
|
public DeviceState getDeviceState() {
|
||||||
|
if(deviceState == null)
|
||||||
|
deviceState = DeviceState.createDeviceState();
|
||||||
return deviceState;
|
return deviceState;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDeviceState(boolean deviceState) {
|
public void setDeviceState(DeviceState deviceState) {
|
||||||
this.deviceState = deviceState;
|
this.deviceState = deviceState;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getDeviceSetValue() {
|
|
||||||
return deviceSetValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDeviceSetValue(int deviceSetValue) {
|
|
||||||
this.deviceSetValue = deviceSetValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import com.bwssystems.HABridge.dao.DeviceRepository;
|
|||||||
import com.bwssystems.HABridge.dao.ErrorMessage;
|
import com.bwssystems.HABridge.dao.ErrorMessage;
|
||||||
import com.bwssystems.NestBridge.NestHome;
|
import com.bwssystems.NestBridge.NestHome;
|
||||||
import com.bwssystems.harmony.HarmonyHome;
|
import com.bwssystems.harmony.HarmonyHome;
|
||||||
|
import com.bwssystems.hue.HueHome;
|
||||||
import com.bwssystems.luupRequests.Device;
|
import com.bwssystems.luupRequests.Device;
|
||||||
import com.bwssystems.luupRequests.Scene;
|
import com.bwssystems.luupRequests.Scene;
|
||||||
import com.bwssystems.util.JsonTransformer;
|
import com.bwssystems.util.JsonTransformer;
|
||||||
@@ -38,9 +39,10 @@ public class DeviceResource {
|
|||||||
private VeraHome veraHome;
|
private VeraHome veraHome;
|
||||||
private HarmonyHome myHarmonyHome;
|
private HarmonyHome myHarmonyHome;
|
||||||
private NestHome nestHome;
|
private NestHome nestHome;
|
||||||
|
private HueHome hueHome;
|
||||||
private static final Set<String> supportedVerbs = new HashSet<>(Arrays.asList("get", "put", "post"));
|
private static final Set<String> supportedVerbs = new HashSet<>(Arrays.asList("get", "put", "post"));
|
||||||
|
|
||||||
public DeviceResource(BridgeSettingsDescriptor theSettings, HarmonyHome theHarmonyHome, NestHome aNestHome) {
|
public DeviceResource(BridgeSettingsDescriptor theSettings, HarmonyHome theHarmonyHome, NestHome aNestHome, HueHome aHueHome) {
|
||||||
this.deviceRepository = new DeviceRepository(theSettings.getUpnpDeviceDb());
|
this.deviceRepository = new DeviceRepository(theSettings.getUpnpDeviceDb());
|
||||||
|
|
||||||
if(theSettings.isValidVera())
|
if(theSettings.isValidVera())
|
||||||
@@ -57,6 +59,11 @@ public class DeviceResource {
|
|||||||
this.nestHome = aNestHome;
|
this.nestHome = aNestHome;
|
||||||
else
|
else
|
||||||
this.nestHome = null;
|
this.nestHome = null;
|
||||||
|
|
||||||
|
if(theSettings.isValidHue())
|
||||||
|
this.hueHome = aHueHome;
|
||||||
|
else
|
||||||
|
this.hueHome = null;
|
||||||
setupEndpoints();
|
setupEndpoints();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,6 +252,16 @@ public class DeviceResource {
|
|||||||
return nestHome.getItems();
|
return nestHome.getItems();
|
||||||
}, new JsonTransformer());
|
}, new JsonTransformer());
|
||||||
|
|
||||||
|
get (API_CONTEXT + "/hue/devices", "application/json", (request, response) -> {
|
||||||
|
log.debug("Get hue items");
|
||||||
|
if(hueHome == null) {
|
||||||
|
response.status(HttpStatus.SC_NOT_FOUND);
|
||||||
|
return new ErrorMessage("A Hue is not available.");
|
||||||
|
}
|
||||||
|
response.status(HttpStatus.SC_OK);
|
||||||
|
return hueHome.getDevices();
|
||||||
|
}, new JsonTransformer());
|
||||||
|
|
||||||
get (API_CONTEXT + "/backup/available", "application/json", (request, response) -> {
|
get (API_CONTEXT + "/backup/available", "application/json", (request, response) -> {
|
||||||
log.debug("Get backup filenames");
|
log.debug("Get backup filenames");
|
||||||
response.status(HttpStatus.SC_OK);
|
response.status(HttpStatus.SC_OK);
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package com.bwssystems.HABridge.hue;
|
package com.bwssystems.HABridge.hue;
|
||||||
|
|
||||||
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
||||||
|
import com.bwssystems.HABridge.api.CallItem;
|
||||||
|
import com.bwssystems.HABridge.api.NameValue;
|
||||||
import com.bwssystems.HABridge.api.UserCreateRequest;
|
import com.bwssystems.HABridge.api.UserCreateRequest;
|
||||||
import com.bwssystems.HABridge.api.hue.DeviceResponse;
|
import com.bwssystems.HABridge.api.hue.DeviceResponse;
|
||||||
import com.bwssystems.HABridge.api.hue.DeviceState;
|
import com.bwssystems.HABridge.api.hue.DeviceState;
|
||||||
@@ -12,6 +14,10 @@ import com.bwssystems.harmony.ButtonPress;
|
|||||||
import com.bwssystems.harmony.HarmonyHandler;
|
import com.bwssystems.harmony.HarmonyHandler;
|
||||||
import com.bwssystems.harmony.HarmonyHome;
|
import com.bwssystems.harmony.HarmonyHome;
|
||||||
import com.bwssystems.harmony.RunActivity;
|
import com.bwssystems.harmony.RunActivity;
|
||||||
|
import com.bwssystems.hue.HueDeviceIdentifier;
|
||||||
|
import com.bwssystems.hue.HueErrorStringSet;
|
||||||
|
import com.bwssystems.hue.HueHome;
|
||||||
|
import com.bwssystems.hue.HueUtil;
|
||||||
import com.bwssystems.nest.controller.Nest;
|
import com.bwssystems.nest.controller.Nest;
|
||||||
import com.bwssystems.util.JsonTransformer;
|
import com.bwssystems.util.JsonTransformer;
|
||||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
@@ -28,34 +34,44 @@ import static spark.Spark.put;
|
|||||||
import org.apache.http.HttpResponse;
|
import org.apache.http.HttpResponse;
|
||||||
import org.apache.http.HttpStatus;
|
import org.apache.http.HttpStatus;
|
||||||
import org.apache.http.client.HttpClient;
|
import org.apache.http.client.HttpClient;
|
||||||
|
import org.apache.http.client.config.CookieSpecs;
|
||||||
|
import org.apache.http.client.config.RequestConfig;
|
||||||
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.client.methods.HttpPost;
|
||||||
import org.apache.http.client.methods.HttpPut;
|
import org.apache.http.client.methods.HttpPut;
|
||||||
import org.apache.http.client.methods.HttpUriRequest;
|
import org.apache.http.client.methods.HttpUriRequest;
|
||||||
|
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
||||||
import org.apache.http.entity.ContentType;
|
import org.apache.http.entity.ContentType;
|
||||||
import org.apache.http.entity.StringEntity;
|
import org.apache.http.entity.StringEntity;
|
||||||
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
import org.apache.http.impl.client.HttpClients;
|
import org.apache.http.impl.client.HttpClients;
|
||||||
|
import org.apache.http.ssl.SSLContexts;
|
||||||
import org.apache.http.util.EntityUtils;
|
import org.apache.http.util.EntityUtils;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.math.BigInteger;
|
||||||
import java.net.DatagramPacket;
|
import java.net.DatagramPacket;
|
||||||
import java.net.DatagramSocket;
|
import java.net.DatagramSocket;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
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 javax.net.ssl.SSLContext;
|
||||||
import javax.xml.bind.DatatypeConverter;
|
import javax.xml.bind.DatatypeConverter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Based on Armzilla's HueMulator - a Philips Hue emulator using sparkjava rest server
|
* Based on Armzilla's HueMulator - a Philips Hue emulator using sparkjava rest server
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class HueMulator {
|
public class HueMulator implements HueErrorStringSet {
|
||||||
private static final Logger log = LoggerFactory.getLogger(HueMulator.class);
|
private static final Logger log = LoggerFactory.getLogger(HueMulator.class);
|
||||||
private static final String INTENSITY_PERCENT = "${intensity.percent}";
|
private static final String INTENSITY_PERCENT = "${intensity.percent}";
|
||||||
private static final String INTENSITY_BYTE = "${intensity.byte}";
|
private static final String INTENSITY_BYTE = "${intensity.byte}";
|
||||||
@@ -67,14 +83,37 @@ public class HueMulator {
|
|||||||
private DeviceRepository repository;
|
private DeviceRepository repository;
|
||||||
private HarmonyHome myHarmonyHome;
|
private HarmonyHome myHarmonyHome;
|
||||||
private Nest theNest;
|
private Nest theNest;
|
||||||
|
private HueHome myHueHome;
|
||||||
private HttpClient httpClient;
|
private HttpClient httpClient;
|
||||||
|
private CloseableHttpClient httpclientSSL;
|
||||||
|
private SSLContext sslcontext;
|
||||||
|
private SSLConnectionSocketFactory sslsf;
|
||||||
|
private RequestConfig globalConfig;
|
||||||
private ObjectMapper mapper;
|
private ObjectMapper mapper;
|
||||||
private BridgeSettingsDescriptor bridgeSettings;
|
private BridgeSettingsDescriptor bridgeSettings;
|
||||||
private byte[] sendData;
|
private byte[] sendData;
|
||||||
|
private String hueUser;
|
||||||
|
private String errorString;
|
||||||
|
|
||||||
|
|
||||||
public HueMulator(BridgeSettingsDescriptor theBridgeSettings, DeviceRepository aDeviceRepository, HarmonyHome theHarmonyHome, NestHome aNestHome){
|
public HueMulator(BridgeSettingsDescriptor theBridgeSettings, DeviceRepository aDeviceRepository, HarmonyHome theHarmonyHome, NestHome aNestHome, HueHome aHueHome){
|
||||||
httpClient = HttpClients.createDefault();
|
httpClient = HttpClients.createDefault();
|
||||||
|
// Trust own CA and all self-signed certs
|
||||||
|
sslcontext = SSLContexts.createDefault();
|
||||||
|
// Allow TLSv1 protocol only
|
||||||
|
sslsf = new SSLConnectionSocketFactory(
|
||||||
|
sslcontext,
|
||||||
|
new String[] { "TLSv1" },
|
||||||
|
null,
|
||||||
|
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
|
||||||
|
globalConfig = RequestConfig.custom()
|
||||||
|
.setCookieSpec(CookieSpecs.STANDARD)
|
||||||
|
.build();
|
||||||
|
httpclientSSL = HttpClients.custom()
|
||||||
|
.setSSLSocketFactory(sslsf)
|
||||||
|
.setDefaultRequestConfig(globalConfig)
|
||||||
|
.build();
|
||||||
|
|
||||||
mapper = new ObjectMapper(); //armzilla: work around Echo incorrect content type and breaking mapping. Map manually
|
mapper = new ObjectMapper(); //armzilla: work around Echo incorrect content type and breaking mapping. Map manually
|
||||||
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||||
repository = aDeviceRepository;
|
repository = aDeviceRepository;
|
||||||
@@ -86,7 +125,13 @@ public class HueMulator {
|
|||||||
this.theNest = aNestHome.getTheNest();
|
this.theNest = aNestHome.getTheNest();
|
||||||
else
|
else
|
||||||
this.theNest = null;
|
this.theNest = null;
|
||||||
|
if(theBridgeSettings.isValidHue())
|
||||||
|
this.myHueHome = aHueHome;
|
||||||
|
else
|
||||||
|
this.myHueHome = null;
|
||||||
bridgeSettings = theBridgeSettings;
|
bridgeSettings = theBridgeSettings;
|
||||||
|
hueUser = null;
|
||||||
|
errorString = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function sets up the sparkjava rest calls for the hue api
|
// This function sets up the sparkjava rest calls for the hue api
|
||||||
@@ -289,24 +334,9 @@ public class HueMulator {
|
|||||||
responseString = "[{\"error\":{\"type\": 3, \"address\": \"/lights/" + lightId + "\",\"description\": \"Could not find device\", \"resource\": \"/lights/" + lightId + "\"}}]";
|
responseString = "[{\"error\":{\"type\": 3, \"address\": \"/lights/" + lightId + "\",\"description\": \"Could not find device\", \"resource\": \"/lights/" + lightId + "\"}}]";
|
||||||
return responseString;
|
return responseString;
|
||||||
}
|
}
|
||||||
|
|
||||||
responseString = "[{\"success\":{\"/lights/" + lightId + "/state/on\":";
|
responseString = this.formatSuccessHueResponse(state, request.body(), lightId);
|
||||||
if(request.body().contains("bri"))
|
device.setDeviceState(state);
|
||||||
{
|
|
||||||
responseString = responseString + "true}},{\"success\":{\"/lights/" + lightId + "/state/bri\":" + state.getBri() + "}}]";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (state.isOn()) {
|
|
||||||
responseString = responseString + "true}}]";
|
|
||||||
state.setBri(255);
|
|
||||||
} else if (request.body().contains("false")) {
|
|
||||||
responseString = responseString + "false}}]";
|
|
||||||
state.setBri(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
device.setDeviceSetValue(state.getBri());
|
|
||||||
device.setDeviceState(state.isOn());
|
|
||||||
|
|
||||||
return responseString;
|
return responseString;
|
||||||
});
|
});
|
||||||
@@ -330,6 +360,7 @@ public class HueMulator {
|
|||||||
String lightId = request.params(":id");
|
String lightId = request.params(":id");
|
||||||
String responseString = null;
|
String responseString = null;
|
||||||
String url = null;
|
String url = null;
|
||||||
|
NameValue[] theHeaders = null;
|
||||||
DeviceState state = null;
|
DeviceState state = null;
|
||||||
log.debug("hue state change requested: " + userId + " from " + request.ip() + " body: " + request.body());
|
log.debug("hue state change requested: " + userId + " from " + request.ip() + " body: " + request.body());
|
||||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||||
@@ -350,36 +381,72 @@ public class HueMulator {
|
|||||||
responseString = "[{\"error\":{\"type\": 3, \"address\": \"/lights/" + lightId + "\",\"description\": \"Could not find device\", \"resource\": \"/lights/" + lightId + "\"}}]";
|
responseString = "[{\"error\":{\"type\": 3, \"address\": \"/lights/" + lightId + "\",\"description\": \"Could not find device\", \"resource\": \"/lights/" + lightId + "\"}}]";
|
||||||
return responseString;
|
return responseString;
|
||||||
}
|
}
|
||||||
|
state.fillIn();
|
||||||
|
|
||||||
|
theHeaders = new Gson().fromJson(device.getHeaders(), NameValue[].class);
|
||||||
|
responseString = this.formatSuccessHueResponse(state, request.body(), lightId);
|
||||||
|
|
||||||
|
if(device.getDeviceType().toLowerCase().contains("hue") || (device.getMapType() != null && device.getMapType().equalsIgnoreCase("hueDevice")))
|
||||||
|
{
|
||||||
|
if(myHueHome != null) {
|
||||||
|
url = device.getOnUrl();
|
||||||
|
HueDeviceIdentifier deviceId = new Gson().fromJson(url, HueDeviceIdentifier.class);
|
||||||
|
if(myHueHome.getTheHUERegisteredUser() == null) {
|
||||||
|
hueUser = HueUtil.registerWithHue(httpClient, deviceId.getIpAddress(), device.getName(), myHueHome.getTheHUERegisteredUser(), this);
|
||||||
|
if(hueUser == null) {
|
||||||
|
return errorString;
|
||||||
|
}
|
||||||
|
myHueHome.setTheHUERegisteredUser(hueUser);
|
||||||
|
}
|
||||||
|
|
||||||
responseString = "[{\"success\":{\"/lights/" + lightId + "/state/on\":";
|
// make call
|
||||||
|
responseString = doHttpRequest("http://"+deviceId.getIpAddress()+"/api/"+myHueHome.getTheHUERegisteredUser()+"/lights/"+deviceId.getDeviceId()+"/state", HttpPut.METHOD_NAME, device.getContentType(), request.body(), null);
|
||||||
|
if (responseString == null) {
|
||||||
|
log.warn("Error on calling url to change device state: " + url);
|
||||||
|
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId + "\",\"description\": \"Error on calling HUE to change device state\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
|
||||||
|
}
|
||||||
|
else if(responseString.contains("[{\"error\":") && responseString.contains("unauthorized user")) {
|
||||||
|
myHueHome.setTheHUERegisteredUser(null);
|
||||||
|
hueUser = HueUtil.registerWithHue(httpClient, deviceId.getIpAddress(), device.getName(), myHueHome.getTheHUERegisteredUser(), this);
|
||||||
|
if(hueUser == null) {
|
||||||
|
return errorString;
|
||||||
|
}
|
||||||
|
myHueHome.setTheHUERegisteredUser(hueUser);
|
||||||
|
}
|
||||||
|
else if(!responseString.contains("[{\"error\":"))
|
||||||
|
device.setDeviceState(state);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId + "\",\"description\": \"No HUE configured\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
|
||||||
|
|
||||||
|
return responseString;
|
||||||
|
}
|
||||||
|
|
||||||
if(request.body().contains("bri"))
|
if(request.body().contains("bri"))
|
||||||
{
|
{
|
||||||
url = device.getDimUrl();
|
url = device.getDimUrl();
|
||||||
|
|
||||||
if(url == null || url.length() == 0)
|
if(url == null || url.length() == 0)
|
||||||
url = device.getOnUrl();
|
url = device.getOnUrl();
|
||||||
|
|
||||||
responseString = responseString + "true}},{\"success\":{\"/lights/" + lightId + "/state/bri\":" + state.getBri() + "}}]";
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (state.isOn()) {
|
if (state.isOn()) {
|
||||||
responseString = responseString + "true}}]";
|
|
||||||
url = device.getOnUrl();
|
url = device.getOnUrl();
|
||||||
state.setBri(255);
|
state.setBri(255);
|
||||||
} else if (request.body().contains("false")) {
|
} else if (request.body().contains("false")) {
|
||||||
responseString = responseString + "false}}]";
|
|
||||||
url = device.getOffUrl();
|
url = device.getOffUrl();
|
||||||
state.setBri(0);
|
state.setBri(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (url == null) {
|
if (url == null) {
|
||||||
log.warn("Could not find url: " + lightId + " for hue state change request: " + userId + " from " + request.ip() + " body: " + request.body());
|
log.warn("Could not find url: " + lightId + " for hue state change request: " + userId + " from " + request.ip() + " body: " + request.body());
|
||||||
responseString = "[{\"error\":{\"type\": 3, \"address\": \"/lights/" + lightId + "\",\"description\": \"Could not find url\", \"resource\": \"/lights/" + lightId + "\"}}]";
|
responseString = "[{\"error\":{\"type\": 3, \"address\": \"/lights/" + lightId + "\",\"description\": \"Could not find url\", \"resource\": \"/lights/" + lightId + "\"}}]";
|
||||||
return responseString;
|
return responseString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if(device.getDeviceType().toLowerCase().contains("activity") || (device.getMapType() != null && device.getMapType().equalsIgnoreCase("harmonyActivity")))
|
if(device.getDeviceType().toLowerCase().contains("activity") || (device.getMapType() != null && device.getMapType().equalsIgnoreCase("harmonyActivity")))
|
||||||
{
|
{
|
||||||
log.debug("executing HUE api request to change activity to Harmony: " + url);
|
log.debug("executing HUE api request to change activity to Harmony: " + url);
|
||||||
@@ -456,9 +523,9 @@ public class HueMulator {
|
|||||||
if(thermoSetting.getControl().equalsIgnoreCase("temp")) {
|
if(thermoSetting.getControl().equalsIgnoreCase("temp")) {
|
||||||
if(request.body().contains("bri")) {
|
if(request.body().contains("bri")) {
|
||||||
if(bridgeSettings.isFarenheit())
|
if(bridgeSettings.isFarenheit())
|
||||||
thermoSetting.setTemp(String.valueOf((Double.parseDouble(replaceIntensityValue(thermoSetting.getTemp(), state.getBri())) - 32.0)/1.8));
|
thermoSetting.setTemp(String.valueOf((Double.parseDouble(replaceIntensityValue(thermoSetting.getTemp(), state.getBri(), false)) - 32.0)/1.8));
|
||||||
else
|
else
|
||||||
thermoSetting.setTemp(String.valueOf(Double.parseDouble(replaceIntensityValue(thermoSetting.getTemp(), state.getBri()))));
|
thermoSetting.setTemp(String.valueOf(Double.parseDouble(replaceIntensityValue(thermoSetting.getTemp(), state.getBri(), false))));
|
||||||
log.debug("Setting thermostat: " + thermoSetting.getName() + " to " + thermoSetting.getTemp() + "C");
|
log.debug("Setting thermostat: " + thermoSetting.getName() + " to " + thermoSetting.getTemp() + "C");
|
||||||
theNest.getThermostat(thermoSetting.getName()).setTargetTemperature(Float.parseFloat(thermoSetting.getTemp()));
|
theNest.getThermostat(thermoSetting.getName()).setTargetTemperature(Float.parseFloat(thermoSetting.getTemp()));
|
||||||
}
|
}
|
||||||
@@ -477,49 +544,109 @@ public class HueMulator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(url.startsWith("udp://"))
|
else if(device.getDeviceType().startsWith("exec")) {
|
||||||
{
|
log.debug("Exec Request called with url: " + url);
|
||||||
log.debug("executing HUE api request to UDP: " + url);
|
if(!url.startsWith("[")) {
|
||||||
try {
|
if(url.startsWith("{\"item"))
|
||||||
String intermediate = url.substring(6);
|
url = "[" + url + "]";
|
||||||
String ipAddr = intermediate.substring(0, intermediate.indexOf(':'));
|
|
||||||
String port = intermediate.substring(intermediate.indexOf(':') + 1, intermediate.indexOf('/'));
|
|
||||||
String theBody = intermediate.substring(intermediate.indexOf('/')+1);
|
|
||||||
DatagramSocket responseSocket = new DatagramSocket(Integer.parseInt(port));
|
|
||||||
if(theBody.startsWith("0x")) {
|
|
||||||
sendData = DatatypeConverter.parseHexBinary(theBody.substring(2));
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
sendData = theBody.getBytes();
|
url = "[{\"item\":\"" + url +"\"}]";
|
||||||
InetAddress IPAddress = InetAddress.getByName(ipAddr);
|
}
|
||||||
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, Integer.parseInt(port));
|
CallItem[] callItems = new Gson().fromJson(url, CallItem[].class);
|
||||||
responseSocket.send(sendPacket);
|
for(int i = 0; i < callItems.length; i++) {
|
||||||
responseSocket.close();
|
if( i > 0) {
|
||||||
} catch (IOException e) {
|
Thread.sleep(bridgeSettings.getButtonsleep());
|
||||||
log.warn("Could not send UDP Datagram packet for request.", e);
|
}
|
||||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId + "\",\"description\": \"Error on calling out to device\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
|
try {
|
||||||
}
|
log.debug("Executing request: " + callItems[i].getItem());
|
||||||
|
Process p = Runtime.getRuntime().exec(replaceIntensityValue(callItems[i].getItem(), state.getBri(), false));
|
||||||
|
log.debug("Process running: " + p.isAlive());
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.warn("Could not execute request: " + callItems[i].getItem(), e);
|
||||||
|
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId + "\",\"description\": \"Error on calling out to device\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
|
||||||
|
i = callItems.length+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else // This section allows the usage of http/tcp/udp calls in a given set of items
|
||||||
{
|
{
|
||||||
log.debug("executing HUE api request to Http " + (device.getHttpVerb() == null?"GET":device.getHttpVerb()) + ": " + url);
|
log.debug("executing HUE api request for network call: " + url);
|
||||||
// quick template
|
if(!url.startsWith("[")) {
|
||||||
String body;
|
if(url.startsWith("{\"item"))
|
||||||
url = replaceIntensityValue(url, state.getBri());
|
url = "[" + url + "]";
|
||||||
if (state.isOn())
|
else
|
||||||
body = replaceIntensityValue(device.getContentBody(), state.getBri());
|
url = "[{\"item\":\"" + url +"\"}]";
|
||||||
else
|
}
|
||||||
body = replaceIntensityValue(device.getContentBodyOff(), state.getBri());
|
CallItem[] callItems = new Gson().fromJson(url, CallItem[].class);
|
||||||
// make call
|
for(int i = 0; i < callItems.length; i++) {
|
||||||
if (!doHttpRequest(url, device.getHttpVerb(), device.getContentType(), body)) {
|
if( i > 0) {
|
||||||
log.warn("Error on calling url to change device state: " + url);
|
Thread.sleep(bridgeSettings.getButtonsleep());
|
||||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId + "\",\"description\": \"Error on calling url to change device state\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
|
}
|
||||||
}
|
try {
|
||||||
|
if(callItems[i].getItem().contains("udp://") || callItems[i].getItem().contains("tcp://")) {
|
||||||
|
String intermediate = callItems[i].getItem().substring(callItems[i].getItem().indexOf("://") + 3);
|
||||||
|
String hostPortion = intermediate.substring(0, intermediate.indexOf('/'));
|
||||||
|
String theUrlBody = intermediate.substring(intermediate.indexOf('/')+1);
|
||||||
|
String hostAddr = null;
|
||||||
|
String port = null;
|
||||||
|
if(hostPortion.contains(":")) {
|
||||||
|
hostAddr = hostPortion.substring(0, intermediate.indexOf(':'));
|
||||||
|
port = hostPortion.substring(intermediate.indexOf(':') + 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
hostAddr = hostPortion;
|
||||||
|
InetAddress IPAddress = InetAddress.getByName(hostAddr);;
|
||||||
|
if(theUrlBody.startsWith("0x")) {
|
||||||
|
theUrlBody = replaceIntensityValue(theUrlBody, state.getBri(), true);
|
||||||
|
sendData = DatatypeConverter.parseHexBinary(theUrlBody.substring(2));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
theUrlBody = replaceIntensityValue(theUrlBody, state.getBri(), false);
|
||||||
|
sendData = theUrlBody.getBytes();
|
||||||
|
}
|
||||||
|
if(callItems[i].getItem().contains("udp://")) {
|
||||||
|
log.debug("executing HUE api request to UDP: " + callItems[i].getItem());
|
||||||
|
DatagramSocket responseSocket = new DatagramSocket(Integer.parseInt(port));
|
||||||
|
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, Integer.parseInt(port));
|
||||||
|
responseSocket.send(sendPacket);
|
||||||
|
responseSocket.close();
|
||||||
|
}
|
||||||
|
else if(callItems[i].getItem().contains("tcp://"))
|
||||||
|
{
|
||||||
|
log.debug("executing HUE api request to TCP: " + callItems[i].getItem());
|
||||||
|
Socket dataSendSocket = new Socket(IPAddress, Integer.parseInt(port));
|
||||||
|
DataOutputStream outToClient = new DataOutputStream(dataSendSocket.getOutputStream());
|
||||||
|
outToClient.write(sendData);
|
||||||
|
outToClient.flush();
|
||||||
|
dataSendSocket.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log.debug("executing HUE api request to Http " + (device.getHttpVerb() == null?"GET":device.getHttpVerb()) + ": " + callItems[i].getItem());
|
||||||
|
|
||||||
|
String anUrl = replaceIntensityValue(callItems[i].getItem(), state.getBri(), false);
|
||||||
|
String body;
|
||||||
|
if (state.isOn())
|
||||||
|
body = replaceIntensityValue(device.getContentBody(), state.getBri(), false);
|
||||||
|
else
|
||||||
|
body = replaceIntensityValue(device.getContentBodyOff(), state.getBri(), false);
|
||||||
|
// make call
|
||||||
|
if (doHttpRequest(anUrl, device.getHttpVerb(), device.getContentType(), body, theHeaders) == null) {
|
||||||
|
log.warn("Error on calling url to change device state: " + anUrl);
|
||||||
|
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId + "\",\"description\": \"Error on calling url to change device state\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
|
||||||
|
i = callItems.length+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("Change device state, Could not send data for network request: " + callItems[i].getItem() + " with Message: " + e.getMessage());
|
||||||
|
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId + "\",\"description\": \"Error on calling out to device\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
|
||||||
|
i = callItems.length+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!responseString.contains("[{\"error\":")) {
|
if(!responseString.contains("[{\"error\":")) {
|
||||||
device.setDeviceSetValue(state.getBri());
|
device.setDeviceState(state);
|
||||||
device.setDeviceState(state.isOn());
|
|
||||||
}
|
}
|
||||||
return responseString;
|
return responseString;
|
||||||
});
|
});
|
||||||
@@ -533,18 +660,34 @@ public class HueMulator {
|
|||||||
* intensity.percent : 0-100, adjusted for the vera
|
* intensity.percent : 0-100, adjusted for the vera
|
||||||
* intensity.math(X*1) : where X is the value from the interface call and can use net.java.dev.eval math
|
* intensity.math(X*1) : where X is the value from the interface call and can use net.java.dev.eval math
|
||||||
*/
|
*/
|
||||||
protected String replaceIntensityValue(String request, int intensity){
|
protected String replaceIntensityValue(String request, int intensity, boolean isHex){
|
||||||
if(request == null){
|
if(request == null){
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
if(request.contains(INTENSITY_BYTE)){
|
if(request.contains(INTENSITY_BYTE)) {
|
||||||
String intensityByte = String.valueOf(intensity);
|
if(isHex) {
|
||||||
request = request.replace(INTENSITY_BYTE, intensityByte);
|
BigInteger bigInt = BigInteger.valueOf(intensity);
|
||||||
}else if(request.contains(INTENSITY_PERCENT)){
|
byte[] theBytes = bigInt.toByteArray();
|
||||||
|
String hexValue = DatatypeConverter.printHexBinary(theBytes);
|
||||||
|
request = request.replace(INTENSITY_BYTE, hexValue);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
String intensityByte = String.valueOf(intensity);
|
||||||
|
request = request.replace(INTENSITY_BYTE, intensityByte);
|
||||||
|
}
|
||||||
|
} else if(request.contains(INTENSITY_PERCENT)) {
|
||||||
int percentBrightness = (int) Math.round(intensity/255.0*100);
|
int percentBrightness = (int) Math.round(intensity/255.0*100);
|
||||||
String intensityPercent = String.valueOf(percentBrightness);
|
if(isHex) {
|
||||||
request = request.replace(INTENSITY_PERCENT, intensityPercent);
|
BigInteger bigInt = BigInteger.valueOf(percentBrightness);
|
||||||
} else if(request.contains(INTENSITY_MATH)){
|
byte[] theBytes = bigInt.toByteArray();
|
||||||
|
String hexValue = DatatypeConverter.printHexBinary(theBytes);
|
||||||
|
request = request.replace(INTENSITY_PERCENT, hexValue);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
String intensityPercent = String.valueOf(percentBrightness);
|
||||||
|
request = request.replace(INTENSITY_PERCENT, intensityPercent);
|
||||||
|
}
|
||||||
|
} else if(request.contains(INTENSITY_MATH)) {
|
||||||
Map<String, BigDecimal> variables = new HashMap<String, BigDecimal>();
|
Map<String, BigDecimal> variables = new HashMap<String, BigDecimal>();
|
||||||
String mathDescriptor = request.substring(request.indexOf(INTENSITY_MATH) + INTENSITY_MATH.length(),request.indexOf(INTENSITY_MATH_CLOSE));
|
String mathDescriptor = request.substring(request.indexOf(INTENSITY_MATH) + INTENSITY_MATH.length(),request.indexOf(INTENSITY_MATH_CLOSE));
|
||||||
variables.put(INTENSITY_MATH_VALUE, new BigDecimal(intensity));
|
variables.put(INTENSITY_MATH_VALUE, new BigDecimal(intensity));
|
||||||
@@ -554,7 +697,15 @@ public class HueMulator {
|
|||||||
Expression exp = new Expression(mathDescriptor);
|
Expression exp = new Expression(mathDescriptor);
|
||||||
BigDecimal result = exp.eval(variables);
|
BigDecimal result = exp.eval(variables);
|
||||||
Integer endResult = Math.round(result.floatValue());
|
Integer endResult = Math.round(result.floatValue());
|
||||||
request = request.replace(INTENSITY_MATH + mathDescriptor + INTENSITY_MATH_CLOSE, endResult.toString());
|
if(isHex) {
|
||||||
|
BigInteger bigInt = BigInteger.valueOf(endResult);
|
||||||
|
byte[] theBytes = bigInt.toByteArray();
|
||||||
|
String hexValue = DatatypeConverter.printHexBinary(theBytes);
|
||||||
|
request = request.replace(INTENSITY_MATH + mathDescriptor + INTENSITY_MATH_CLOSE, hexValue);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
request = request.replace(INTENSITY_MATH + mathDescriptor + INTENSITY_MATH_CLOSE, endResult.toString());
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("Could not execute Math: " + mathDescriptor, e);
|
log.warn("Could not execute Math: " + mathDescriptor, e);
|
||||||
}
|
}
|
||||||
@@ -563,35 +714,126 @@ public class HueMulator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// This function executes the url from the device repository against the vera
|
// This function executes the url from the device repository against the target as http or https as defined
|
||||||
protected boolean doHttpRequest(String url, String httpVerb, String contentType, String body) {
|
protected String doHttpRequest(String url, String httpVerb, String contentType, String body, NameValue[] headers) {
|
||||||
HttpUriRequest request = null;
|
HttpUriRequest request = null;
|
||||||
if(HttpGet.METHOD_NAME.equalsIgnoreCase(httpVerb) || httpVerb == null) {
|
String theContent = null;
|
||||||
request = new HttpGet(url);
|
try {
|
||||||
}else if(HttpPost.METHOD_NAME.equalsIgnoreCase(httpVerb)){
|
if(HttpGet.METHOD_NAME.equalsIgnoreCase(httpVerb) || httpVerb == null) {
|
||||||
HttpPost postRequest = new HttpPost(url);
|
request = new HttpGet(url);
|
||||||
ContentType parsedContentType = ContentType.parse(contentType);
|
}else if(HttpPost.METHOD_NAME.equalsIgnoreCase(httpVerb)){
|
||||||
StringEntity requestBody = new StringEntity(body, parsedContentType);
|
HttpPost postRequest = new HttpPost(url);
|
||||||
postRequest.setEntity(requestBody);
|
ContentType parsedContentType = ContentType.parse(contentType);
|
||||||
request = postRequest;
|
StringEntity requestBody = new StringEntity(body, parsedContentType);
|
||||||
}else if(HttpPut.METHOD_NAME.equalsIgnoreCase(httpVerb)){
|
postRequest.setEntity(requestBody);
|
||||||
HttpPut putRequest = new HttpPut(url);
|
request = postRequest;
|
||||||
ContentType parsedContentType = ContentType.parse(contentType);
|
}else if(HttpPut.METHOD_NAME.equalsIgnoreCase(httpVerb)){
|
||||||
StringEntity requestBody = new StringEntity(body, parsedContentType);
|
HttpPut putRequest = new HttpPut(url);
|
||||||
putRequest.setEntity(requestBody);
|
ContentType parsedContentType = ContentType.parse(contentType);
|
||||||
request = putRequest;
|
StringEntity requestBody = new StringEntity(body, parsedContentType);
|
||||||
|
putRequest.setEntity(requestBody);
|
||||||
|
request = putRequest;
|
||||||
|
}
|
||||||
|
} catch(IllegalArgumentException e) {
|
||||||
|
log.warn("Error calling out to HA gateway: IllegalArgumentException in log", e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
log.debug("Making outbound call in doHttpRequest: " + request);
|
log.debug("Making outbound call in doHttpRequest: " + request);
|
||||||
try {
|
try {
|
||||||
HttpResponse response = httpClient.execute(request);
|
if(headers != null && headers.length > 0) {
|
||||||
EntityUtils.consume(response.getEntity()); //close out inputstream ignore content
|
for(int i = 0; i < headers.length; i++) {
|
||||||
|
request.setHeader(headers[i].getName(), headers[i].getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HttpResponse response;
|
||||||
|
if(url.startsWith("https"))
|
||||||
|
response = httpclientSSL.execute(request);
|
||||||
|
else
|
||||||
|
response = httpClient.execute(request);
|
||||||
log.debug((httpVerb == null?"GET":httpVerb) + " execute on URL responded: " + response.getStatusLine().getStatusCode());
|
log.debug((httpVerb == null?"GET":httpVerb) + " execute on URL responded: " + response.getStatusLine().getStatusCode());
|
||||||
if(response.getStatusLine().getStatusCode() == 200){
|
if(response.getStatusLine().getStatusCode() >= 200 && response.getStatusLine().getStatusCode() < 300){
|
||||||
return true;
|
if(response.getEntity() != null ) {
|
||||||
|
theContent = EntityUtils.toString(response.getEntity(), Charset.forName("UTF-8")); //read content for data
|
||||||
|
EntityUtils.consume(response.getEntity()); //close out inputstream ignore content
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.warn("Error calling out to HA gateway", e);
|
log.warn("Error calling out to HA gateway: IOException in log", e);
|
||||||
}
|
}
|
||||||
return false;
|
return theContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String formatSuccessHueResponse(DeviceState state, String body, String lightId) {
|
||||||
|
|
||||||
|
String responseString = "[{\"success\":{\"/lights/" + lightId + "/state/on\":";
|
||||||
|
boolean justState = true;
|
||||||
|
if(body.contains("bri"))
|
||||||
|
{
|
||||||
|
if(justState)
|
||||||
|
responseString = responseString + "true}}";
|
||||||
|
responseString = responseString + ",{\"success\":{\"/lights/" + lightId + "/state/bri\":" + state.getBri() + "}}";
|
||||||
|
justState = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(body.contains("ct"))
|
||||||
|
{
|
||||||
|
if(justState)
|
||||||
|
responseString = responseString + "true}}";
|
||||||
|
responseString = responseString + ",{\"success\":{\"/lights/" + lightId + "/state/ct\":" + state.getCt() + "}}";
|
||||||
|
justState = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(body.contains("xy"))
|
||||||
|
{
|
||||||
|
if(justState)
|
||||||
|
responseString = responseString + "true}}";
|
||||||
|
responseString = responseString + ",{\"success\":{\"/lights/" + lightId + "/state/xy\":" + state.getXy() + "}}";
|
||||||
|
justState = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(body.contains("hue"))
|
||||||
|
{
|
||||||
|
if(justState)
|
||||||
|
responseString = responseString + "true}}";
|
||||||
|
responseString = responseString + ",{\"success\":{\"/lights/" + lightId + "/state/hue\":" + state.getHue() + "}}";
|
||||||
|
justState = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(body.contains("sat"))
|
||||||
|
{
|
||||||
|
if(justState)
|
||||||
|
responseString = responseString + "true}}";
|
||||||
|
responseString = responseString + ",{\"success\":{\"/lights/" + lightId + "/state/sat\":" + state.getSat() + "}}";
|
||||||
|
justState = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(body.contains("colormode"))
|
||||||
|
{
|
||||||
|
if(justState)
|
||||||
|
responseString = responseString + "true}}";
|
||||||
|
responseString = responseString + ",{\"success\":{\"/lights/" + lightId + "/state/colormode\":" + state.getColormode() + "}}";
|
||||||
|
justState = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(justState)
|
||||||
|
{
|
||||||
|
if (state.isOn()) {
|
||||||
|
responseString = responseString + "true}}";
|
||||||
|
state.setBri(255);
|
||||||
|
} else if (body.contains("false")) {
|
||||||
|
responseString = responseString + "false}}";
|
||||||
|
state.setBri(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
responseString = responseString + "]";
|
||||||
|
|
||||||
|
return responseString;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setErrorString(String anError) {
|
||||||
|
errorString = anError;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,69 +33,121 @@ public class UpnpListener {
|
|||||||
bridgeControl = theControl;
|
bridgeControl = theControl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("resource")
|
||||||
public boolean startListening(){
|
public boolean startListening(){
|
||||||
log.info("UPNP Discovery Listener starting....");
|
log.info("UPNP Discovery Listener starting....");
|
||||||
|
DatagramSocket responseSocket = null;
|
||||||
|
MulticastSocket upnpMulticastSocket = null;
|
||||||
|
Enumeration<NetworkInterface> ifs = null;
|
||||||
|
|
||||||
try (DatagramSocket responseSocket = new DatagramSocket(upnpResponsePort);
|
boolean portLoopControl = true;
|
||||||
MulticastSocket upnpMulticastSocket = new MulticastSocket(Configuration.UPNP_DISCOVERY_PORT);) {
|
int retryCount = 0;
|
||||||
InetSocketAddress socketAddress = new InetSocketAddress(Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT);
|
while(portLoopControl) {
|
||||||
Enumeration<NetworkInterface> ifs = NetworkInterface.getNetworkInterfaces();
|
try {
|
||||||
|
responseSocket = new DatagramSocket(upnpResponsePort);
|
||||||
while (ifs.hasMoreElements()) {
|
if(retryCount > 0)
|
||||||
NetworkInterface xface = ifs.nextElement();
|
log.info("Upnp Response Port issue, found open port: " + upnpResponsePort);
|
||||||
Enumeration<InetAddress> addrs = xface.getInetAddresses();
|
portLoopControl = false;
|
||||||
String name = xface.getName();
|
} catch(SocketException e) {
|
||||||
int IPsPerNic = 0;
|
if(retryCount == 0)
|
||||||
|
log.warn("Upnp Response Port is in use, starting loop to find open port for 20 tries - configured port is: " + upnpResponsePort);
|
||||||
while (addrs.hasMoreElements()) {
|
if(retryCount >= 20) {
|
||||||
InetAddress addr = addrs.nextElement();
|
portLoopControl = false;
|
||||||
if(traceupnp)
|
log.error("Upnp Response Port issue, could not find open port - last port tried: " + upnpResponsePort + " with message: " + e.getMessage());
|
||||||
log.info("Traceupnp: " + name + " ... has addr " + addr);
|
return false;
|
||||||
else
|
|
||||||
log.debug(name + " ... has addr " + addr);
|
|
||||||
if (InetAddressUtils.isIPv4Address(addr.getHostAddress())) {
|
|
||||||
IPsPerNic++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
log.debug("Checking " + name + " to our interface set");
|
}
|
||||||
if (IPsPerNic > 0) {
|
if(portLoopControl) {
|
||||||
|
retryCount++;
|
||||||
|
upnpResponsePort++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
upnpMulticastSocket = new MulticastSocket(Configuration.UPNP_DISCOVERY_PORT);
|
||||||
|
} catch(IOException e){
|
||||||
|
log.error("Upnp Discovery Port is in use, or restricted by admin (try running with sudo or admin privs): " + Configuration.UPNP_DISCOVERY_PORT + " with message: " + e.getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
InetSocketAddress socketAddress = new InetSocketAddress(Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT);
|
||||||
|
try {
|
||||||
|
ifs = NetworkInterface.getNetworkInterfaces();
|
||||||
|
} catch (SocketException e) {
|
||||||
|
log.error("Could not get network interfaces for this machine: " + e.getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (ifs.hasMoreElements()) {
|
||||||
|
NetworkInterface xface = ifs.nextElement();
|
||||||
|
Enumeration<InetAddress> addrs = xface.getInetAddresses();
|
||||||
|
String name = xface.getName();
|
||||||
|
int IPsPerNic = 0;
|
||||||
|
|
||||||
|
while (addrs.hasMoreElements()) {
|
||||||
|
InetAddress addr = addrs.nextElement();
|
||||||
|
if (traceupnp)
|
||||||
|
log.info("Traceupnp: " + name + " ... has addr " + addr);
|
||||||
|
else
|
||||||
|
log.debug(name + " ... has addr " + addr);
|
||||||
|
if (InetAddressUtils.isIPv4Address(addr.getHostAddress())) {
|
||||||
|
IPsPerNic++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.debug("Checking " + name + " to our interface set");
|
||||||
|
if (IPsPerNic > 0) {
|
||||||
|
try {
|
||||||
upnpMulticastSocket.joinGroup(socketAddress, xface);
|
upnpMulticastSocket.joinGroup(socketAddress, xface);
|
||||||
if(traceupnp)
|
if (traceupnp)
|
||||||
log.info("Traceupnp: Adding " + name + " to our interface set");
|
log.info("Traceupnp: Adding " + name + " to our interface set");
|
||||||
else
|
else
|
||||||
log.debug("Adding " + name + " to our interface set");
|
log.debug("Adding " + name + " to our interface set");
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.warn("Multicast join failed for: " + socketAddress.getHostName() + " to interface: "
|
||||||
|
+ xface.getName() + " with message: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("UPNP Discovery Listener running and ready....");
|
|
||||||
boolean loopControl = true;
|
|
||||||
while(loopControl){ //trigger shutdown here
|
|
||||||
byte[] buf = new byte[1024];
|
|
||||||
DatagramPacket packet = new DatagramPacket(buf, buf.length);
|
|
||||||
upnpMulticastSocket.receive(packet);
|
|
||||||
if(isSSDPDiscovery(packet)){
|
|
||||||
sendUpnpResponse(responseSocket, packet.getAddress(), packet.getPort());
|
|
||||||
}
|
|
||||||
if(bridgeControl.isReinit() || bridgeControl.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(bridgeControl.isReinit())
|
|
||||||
|
log.info("UPNP Discovery Listener running and ready....");
|
||||||
|
boolean loopControl = true;
|
||||||
|
boolean error = false;
|
||||||
|
while (loopControl) { // trigger shutdown here
|
||||||
|
byte[] buf = new byte[1024];
|
||||||
|
DatagramPacket packet = new DatagramPacket(buf, buf.length);
|
||||||
|
try {
|
||||||
|
upnpMulticastSocket.receive(packet);
|
||||||
|
if (isSSDPDiscovery(packet)) {
|
||||||
|
try {
|
||||||
|
sendUpnpResponse(responseSocket, packet.getAddress(), packet.getPort());
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("UpnpListener encountered an error sending upnp response packet. Shutting down", e);
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("UpnpListener encountered an error reading socket. Shutting down", e);
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
if (error || bridgeControl.isReinit() || bridgeControl.isStop()) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(1000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// noop
|
||||||
|
}
|
||||||
|
loopControl = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
upnpMulticastSocket.close();
|
||||||
|
responseSocket.close();
|
||||||
|
if (bridgeControl.isReinit())
|
||||||
log.info("UPNP Discovery Listener - ended, restart found");
|
log.info("UPNP Discovery Listener - ended, restart found");
|
||||||
if(bridgeControl.isStop())
|
if (bridgeControl.isStop())
|
||||||
log.info("UPNP Discovery Listener - ended, stop found");
|
log.info("UPNP Discovery Listener - ended, stop found");
|
||||||
if(!bridgeControl.isStop()&& !bridgeControl.isReinit())
|
if (!bridgeControl.isStop() && !bridgeControl.isReinit()) {
|
||||||
log.info("UPNP Discovery Listener - ended, error found");
|
log.info("UPNP Discovery Listener - ended, error found");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return bridgeControl.isReinit();
|
return bridgeControl.isReinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
35
src/main/java/com/bwssystems/hue/HueDevice.java
Normal file
35
src/main/java/com/bwssystems/hue/HueDevice.java
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package com.bwssystems.hue;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.api.hue.DeviceResponse;
|
||||||
|
|
||||||
|
|
||||||
|
public class HueDevice {
|
||||||
|
private DeviceResponse device;
|
||||||
|
private String huedeviceid;
|
||||||
|
private String hueaddress;
|
||||||
|
private String huename;
|
||||||
|
public DeviceResponse getDevice() {
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
public void setDevice(DeviceResponse adevice) {
|
||||||
|
this.device = adevice;
|
||||||
|
}
|
||||||
|
public String getHuedeviceid() {
|
||||||
|
return huedeviceid;
|
||||||
|
}
|
||||||
|
public void setHuedeviceid(String huedeviceid) {
|
||||||
|
this.huedeviceid = huedeviceid;
|
||||||
|
}
|
||||||
|
public String getHueaddress() {
|
||||||
|
return hueaddress;
|
||||||
|
}
|
||||||
|
public void setHueaddress(String ahueaddress) {
|
||||||
|
this.hueaddress = ahueaddress;
|
||||||
|
}
|
||||||
|
public String getHuename() {
|
||||||
|
return huename;
|
||||||
|
}
|
||||||
|
public void setHuename(String ahuename) {
|
||||||
|
this.huename = ahuename;
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/main/java/com/bwssystems/hue/HueDeviceIdentifier.java
Normal file
18
src/main/java/com/bwssystems/hue/HueDeviceIdentifier.java
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package com.bwssystems.hue;
|
||||||
|
|
||||||
|
public class HueDeviceIdentifier {
|
||||||
|
private String ipAddress;
|
||||||
|
private String deviceId;
|
||||||
|
public String getIpAddress() {
|
||||||
|
return ipAddress;
|
||||||
|
}
|
||||||
|
public void setIpAddress(String ipAddress) {
|
||||||
|
this.ipAddress = ipAddress;
|
||||||
|
}
|
||||||
|
public String getDeviceId() {
|
||||||
|
return deviceId;
|
||||||
|
}
|
||||||
|
public void setDeviceId(String deviceId) {
|
||||||
|
this.deviceId = deviceId;
|
||||||
|
}
|
||||||
|
}
|
||||||
5
src/main/java/com/bwssystems/hue/HueErrorStringSet.java
Normal file
5
src/main/java/com/bwssystems/hue/HueErrorStringSet.java
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
package com.bwssystems.hue;
|
||||||
|
|
||||||
|
public interface HueErrorStringSet {
|
||||||
|
public void setErrorString(String anError);
|
||||||
|
}
|
||||||
73
src/main/java/com/bwssystems/hue/HueHome.java
Normal file
73
src/main/java/com/bwssystems/hue/HueHome.java
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
package com.bwssystems.hue;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
||||||
|
import com.bwssystems.HABridge.NamedIP;
|
||||||
|
import com.bwssystems.HABridge.api.hue.DeviceResponse;
|
||||||
|
import com.bwssystems.HABridge.api.hue.HueApiResponse;
|
||||||
|
|
||||||
|
public class HueHome {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(HueHome.class);
|
||||||
|
private Map<String, HueInfo> hues;
|
||||||
|
private String theHUERegisteredUser;
|
||||||
|
|
||||||
|
public HueHome(BridgeSettingsDescriptor bridgeSettings) {
|
||||||
|
hues = new HashMap<String, HueInfo>();
|
||||||
|
if(!bridgeSettings.isValidHue())
|
||||||
|
return;
|
||||||
|
Iterator<NamedIP> theList = bridgeSettings.getHueaddress().getDevices().iterator();
|
||||||
|
while(theList.hasNext()) {
|
||||||
|
NamedIP aHue = theList.next();
|
||||||
|
hues.put(aHue.getName(), new HueInfo(aHue, this));
|
||||||
|
}
|
||||||
|
theHUERegisteredUser = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<HueDevice> getDevices() {
|
||||||
|
log.debug("consolidating devices for hues");
|
||||||
|
Iterator<String> keys = hues.keySet().iterator();
|
||||||
|
ArrayList<HueDevice> deviceList = new ArrayList<HueDevice>();
|
||||||
|
while(keys.hasNext()) {
|
||||||
|
String key = keys.next();
|
||||||
|
HueApiResponse theResponse = hues.get(key).getHueApiResponse();
|
||||||
|
if(theResponse != null) {
|
||||||
|
Map<String, DeviceResponse> theDevices = theResponse.getLights();
|
||||||
|
if(theDevices != null) {
|
||||||
|
Iterator<String> deviceKeys = theDevices.keySet().iterator();
|
||||||
|
while(deviceKeys.hasNext()) {
|
||||||
|
String theDeviceKey = deviceKeys.next();
|
||||||
|
HueDevice aNewHueDevice = new HueDevice();
|
||||||
|
aNewHueDevice.setDevice(theDevices.get(theDeviceKey));
|
||||||
|
aNewHueDevice.setHuedeviceid(theDeviceKey);
|
||||||
|
aNewHueDevice.setHueaddress(hues.get(key).getHueAddress().getIp());
|
||||||
|
aNewHueDevice.setHuename(key);
|
||||||
|
deviceList.add(aNewHueDevice);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
deviceList = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
log.warn("Cannot get lights for Hue with name: " + key);
|
||||||
|
}
|
||||||
|
return deviceList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTheHUERegisteredUser() {
|
||||||
|
return theHUERegisteredUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTheHUERegisteredUser(String theHUERegisteredUser) {
|
||||||
|
this.theHUERegisteredUser = theHUERegisteredUser;
|
||||||
|
}
|
||||||
|
}
|
||||||
111
src/main/java/com/bwssystems/hue/HueInfo.java
Normal file
111
src/main/java/com/bwssystems/hue/HueInfo.java
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
package com.bwssystems.hue;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import org.apache.http.HttpResponse;
|
||||||
|
import org.apache.http.client.HttpClient;
|
||||||
|
import org.apache.http.client.methods.HttpGet;
|
||||||
|
import org.apache.http.impl.client.HttpClients;
|
||||||
|
import org.apache.http.util.EntityUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.NamedIP;
|
||||||
|
import com.bwssystems.HABridge.api.hue.HueApiResponse;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
|
|
||||||
|
public class HueInfo implements HueErrorStringSet {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(HueInfo.class);
|
||||||
|
private HttpClient httpClient;
|
||||||
|
private NamedIP hueAddress;
|
||||||
|
private String theUser;
|
||||||
|
private HueHome theHueHome;
|
||||||
|
private String errorString = null;
|
||||||
|
|
||||||
|
public HueInfo(NamedIP addressName, HueHome aHueHome) {
|
||||||
|
super();
|
||||||
|
httpClient = HttpClients.createDefault();
|
||||||
|
hueAddress = addressName;
|
||||||
|
theUser = "habridge";
|
||||||
|
theHueHome = aHueHome;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HueApiResponse getHueApiResponse() {
|
||||||
|
HueApiResponse theHueApiResponse = null;
|
||||||
|
|
||||||
|
String theUrl = "http://" + hueAddress.getIp() + HueUtil.HUE_REQUEST + "/" + theUser;
|
||||||
|
String theData;
|
||||||
|
boolean loopControl = true;
|
||||||
|
int retryCount = 0;
|
||||||
|
while(loopControl) {
|
||||||
|
if(retryCount > 3) {
|
||||||
|
log.warn("Max Retry reached to get Hue data from " + hueAddress.getName());
|
||||||
|
loopControl = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
theUrl = "http://" + hueAddress.getIp() + HueUtil.HUE_REQUEST + "/" + theUser;
|
||||||
|
theData = doHttpGETRequest(theUrl);
|
||||||
|
if(theData != null) {
|
||||||
|
log.debug("GET HueApiResponse - data: " + theData);
|
||||||
|
if(theData.contains("[{\"error\":")) {
|
||||||
|
if(theData.contains("unauthorized user")) {
|
||||||
|
theUser = HueUtil.registerWithHue(httpClient, hueAddress.getIp(), hueAddress.getName(), theHueHome.getTheHUERegisteredUser(), this);
|
||||||
|
if(theUser == null) {
|
||||||
|
log.warn("Register to Hue for " + hueAddress.getName() + " returned error: " + errorString);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
theHueHome.setTheHUERegisteredUser(theUser);
|
||||||
|
retryCount++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log.warn("GET HueApiResponse for " + hueAddress.getName() + " - returned error: " + theData);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
theHueApiResponse = new Gson().fromJson(theData, HueApiResponse.class);
|
||||||
|
log.debug("GET HueApiResponse for " + hueAddress.getName() + " - Gson parse - name: " + theHueApiResponse.getConfig().getName() + ", mac addr: " + theHueApiResponse.getConfig().getMac());
|
||||||
|
loopControl = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log.warn("GET HueApiResponse for " + hueAddress.getName() + " - returned null, no data.");
|
||||||
|
loopControl = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return theHueApiResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function executes the url against the vera
|
||||||
|
protected String doHttpGETRequest(String url) {
|
||||||
|
String theContent = null;
|
||||||
|
log.debug("calling GET on URL: " + url);
|
||||||
|
HttpGet httpGet = new HttpGet(url);
|
||||||
|
try {
|
||||||
|
HttpResponse response = httpClient.execute(httpGet);
|
||||||
|
log.debug("GET on URL responded: " + response.getStatusLine().getStatusCode());
|
||||||
|
if(response.getStatusLine().getStatusCode() == 200){
|
||||||
|
theContent = EntityUtils.toString(response.getEntity(), Charset.forName("UTF-8")); //read content for data
|
||||||
|
EntityUtils.consume(response.getEntity()); //close out inputstream ignore content
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("doHttpGETRequest: Error calling out to HA gateway: " + e.getMessage());
|
||||||
|
}
|
||||||
|
return theContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NamedIP getHueAddress() {
|
||||||
|
return hueAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHueAddress(NamedIP hueAddress) {
|
||||||
|
this.hueAddress = hueAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setErrorString(String anError) {
|
||||||
|
errorString = anError;
|
||||||
|
}
|
||||||
|
}
|
||||||
55
src/main/java/com/bwssystems/hue/HueUtil.java
Normal file
55
src/main/java/com/bwssystems/hue/HueUtil.java
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
package com.bwssystems.hue;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.apache.http.HttpResponse;
|
||||||
|
import org.apache.http.client.HttpClient;
|
||||||
|
import org.apache.http.client.methods.HttpPost;
|
||||||
|
import org.apache.http.entity.ContentType;
|
||||||
|
import org.apache.http.entity.StringEntity;
|
||||||
|
import org.apache.http.util.EntityUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.bwssystems.HABridge.api.SuccessUserResponse;
|
||||||
|
import com.bwssystems.HABridge.api.UserCreateRequest;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
|
public class HueUtil {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(HueUtil.class);
|
||||||
|
public static final String HUE_REQUEST = "/api";
|
||||||
|
|
||||||
|
public static final String registerWithHue(HttpClient anHttpClient, String ipAddress, String aName, String theUser, HueErrorStringSet errorStringSet) {
|
||||||
|
UserCreateRequest theLogin = new UserCreateRequest();
|
||||||
|
theLogin.setDevicetype("HABridge#MyMachine");
|
||||||
|
HttpPost postRequest = new HttpPost("http://" + ipAddress + HUE_REQUEST);
|
||||||
|
ContentType parsedContentType = ContentType.parse("application/json");
|
||||||
|
StringEntity requestBody = new StringEntity(new Gson().toJson(theLogin), parsedContentType);
|
||||||
|
HttpResponse response = null;
|
||||||
|
postRequest.setEntity(requestBody);
|
||||||
|
try {
|
||||||
|
response = anHttpClient.execute(postRequest);
|
||||||
|
log.debug("POST execute on URL responded: " + response.getStatusLine().getStatusCode());
|
||||||
|
if(response.getStatusLine().getStatusCode() >= 200 && response.getStatusLine().getStatusCode() < 300){
|
||||||
|
String theBody = EntityUtils.toString(response.getEntity());
|
||||||
|
log.debug("registerWithHue response data: " + theBody);
|
||||||
|
if(theBody.contains("[{\"error\":")) {
|
||||||
|
if(theBody.contains("link button not")) {
|
||||||
|
log.warn("registerWithHue needs link button pressed on HUE bridge: " + aName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
log.warn("registerWithHue returned an unexpected error: " + theBody);
|
||||||
|
errorStringSet.setErrorString(theBody);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SuccessUserResponse[] theResponses = new Gson().fromJson(theBody, SuccessUserResponse[].class); //read content for data, SuccessUserResponse[].class);
|
||||||
|
theUser = theResponses[0].getSuccess().getUsername();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EntityUtils.consume(response.getEntity()); //close out inputstream ignore content
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.warn("Error logging into HUE: IOException in log", e);
|
||||||
|
}
|
||||||
|
return theUser;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
package com.bwssystems.util;
|
|
||||||
|
|
||||||
import java.text.StringCharacterIterator;
|
|
||||||
|
|
||||||
public final class JsonFreeTextStringFormatter {
|
|
||||||
private JsonFreeTextStringFormatter(){
|
|
||||||
//empty - prevent construction
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String forJSON(String aText){
|
|
||||||
final StringBuilder result = new StringBuilder();
|
|
||||||
StringCharacterIterator iterator = new StringCharacterIterator(aText);
|
|
||||||
char character = iterator.current();
|
|
||||||
while (character != StringCharacterIterator.DONE){
|
|
||||||
if( character == '\"' ){
|
|
||||||
result.append("\\\"");
|
|
||||||
}
|
|
||||||
else if(character == '\\'){
|
|
||||||
result.append("\\\\");
|
|
||||||
}
|
|
||||||
else if(character == '/'){
|
|
||||||
result.append("\\/");
|
|
||||||
}
|
|
||||||
else if(character == '\b'){
|
|
||||||
result.append("\\b");
|
|
||||||
}
|
|
||||||
else if(character == '\f'){
|
|
||||||
result.append("\\f");
|
|
||||||
}
|
|
||||||
else if(character == '\n'){
|
|
||||||
result.append("\\n");
|
|
||||||
}
|
|
||||||
else if(character == '\r'){
|
|
||||||
result.append("\\r");
|
|
||||||
}
|
|
||||||
else if(character == '\t'){
|
|
||||||
result.append("\\t");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//the char is not a special one
|
|
||||||
//add it to the result as is
|
|
||||||
result.append(character);
|
|
||||||
}
|
|
||||||
character = iterator.next();
|
|
||||||
}
|
|
||||||
return result.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
259
src/main/java/com/bwssystems/util/TextStringFormatter.java
Normal file
259
src/main/java/com/bwssystems/util/TextStringFormatter.java
Normal file
@@ -0,0 +1,259 @@
|
|||||||
|
package com.bwssystems.util;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.text.CharacterIterator;
|
||||||
|
import java.text.StringCharacterIterator;
|
||||||
|
|
||||||
|
public final class TextStringFormatter {
|
||||||
|
private TextStringFormatter() {
|
||||||
|
// empty - prevent construction
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Escapes characters for text appearing as data in the
|
||||||
|
<a href='http://www.json.org/'>Javascript Object Notation</a>
|
||||||
|
(JSON) data interchange format.
|
||||||
|
|
||||||
|
<P>The following commonly used control characters are escaped :
|
||||||
|
<table border='1' cellpadding='3' cellspacing='0'>
|
||||||
|
<tr><th> Character </th><th> Escaped As </th></tr>
|
||||||
|
<tr><td> " </td><td> \" </td></tr>
|
||||||
|
<tr><td> \ </td><td> \\ </td></tr>
|
||||||
|
<tr><td> / </td><td> \/ </td></tr>
|
||||||
|
<tr><td> back space </td><td> \b </td></tr>
|
||||||
|
<tr><td> form feed </td><td> \f </td></tr>
|
||||||
|
<tr><td> line feed </td><td> \n </td></tr>
|
||||||
|
<tr><td> carriage return </td><td> \r </td></tr>
|
||||||
|
<tr><td> tab </td><td> \t </td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<P>See <a href='http://www.ietf.org/rfc/rfc4627.txt'>RFC 4627</a> for more information.
|
||||||
|
*/
|
||||||
|
public static String forJSON(String aText) {
|
||||||
|
final StringBuilder result = new StringBuilder();
|
||||||
|
StringCharacterIterator iterator = new StringCharacterIterator(aText);
|
||||||
|
char character = iterator.current();
|
||||||
|
while (character != StringCharacterIterator.DONE) {
|
||||||
|
if (character == '\"') {
|
||||||
|
result.append("\\\"");
|
||||||
|
} else if (character == '\\') {
|
||||||
|
result.append("\\\\");
|
||||||
|
} else if (character == '/') {
|
||||||
|
result.append("\\/");
|
||||||
|
} else if (character == '\b') {
|
||||||
|
result.append("\\b");
|
||||||
|
} else if (character == '\f') {
|
||||||
|
result.append("\\f");
|
||||||
|
} else if (character == '\n') {
|
||||||
|
result.append("\\n");
|
||||||
|
} else if (character == '\r') {
|
||||||
|
result.append("\\r");
|
||||||
|
} else if (character == '\t') {
|
||||||
|
result.append("\\t");
|
||||||
|
} else {
|
||||||
|
// the char is not a special one
|
||||||
|
// add it to the result as is
|
||||||
|
result.append(character);
|
||||||
|
}
|
||||||
|
character = iterator.next();
|
||||||
|
}
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Escape characters for text appearing in HTML markup.
|
||||||
|
|
||||||
|
<P>This method exists as a defence against Cross Site Scripting (XSS) hacks.
|
||||||
|
The idea is to neutralize control characters commonly used by scripts, such that
|
||||||
|
they will not be executed by the browser. This is done by replacing the control
|
||||||
|
characters with their escaped equivalents.
|
||||||
|
See {@link hirondelle.web4j.security.SafeText} as well.
|
||||||
|
|
||||||
|
<P>The following characters are replaced with corresponding
|
||||||
|
HTML character entities :
|
||||||
|
<table border='1' cellpadding='3' cellspacing='0'>
|
||||||
|
<tr><th> Character </th><th>Replacement</th></tr>
|
||||||
|
<tr><td> < </td><td> < </td></tr>
|
||||||
|
<tr><td> > </td><td> > </td></tr>
|
||||||
|
<tr><td> & </td><td> & </td></tr>
|
||||||
|
<tr><td> " </td><td> "</td></tr>
|
||||||
|
<tr><td> \t </td><td> 	</td></tr>
|
||||||
|
<tr><td> ! </td><td> !</td></tr>
|
||||||
|
<tr><td> # </td><td> #</td></tr>
|
||||||
|
<tr><td> $ </td><td> $</td></tr>
|
||||||
|
<tr><td> % </td><td> %</td></tr>
|
||||||
|
<tr><td> ' </td><td> '</td></tr>
|
||||||
|
<tr><td> ( </td><td> (</td></tr>
|
||||||
|
<tr><td> ) </td><td> )</td></tr>
|
||||||
|
<tr><td> * </td><td> *</td></tr>
|
||||||
|
<tr><td> + </td><td> + </td></tr>
|
||||||
|
<tr><td> , </td><td> , </td></tr>
|
||||||
|
<tr><td> - </td><td> - </td></tr>
|
||||||
|
<tr><td> . </td><td> . </td></tr>
|
||||||
|
<tr><td> / </td><td> / </td></tr>
|
||||||
|
<tr><td> : </td><td> :</td></tr>
|
||||||
|
<tr><td> ; </td><td> ;</td></tr>
|
||||||
|
<tr><td> = </td><td> =</td></tr>
|
||||||
|
<tr><td> ? </td><td> ?</td></tr>
|
||||||
|
<tr><td> @ </td><td> @</td></tr>
|
||||||
|
<tr><td> [ </td><td> [</td></tr>
|
||||||
|
<tr><td> \ </td><td> \</td></tr>
|
||||||
|
<tr><td> ] </td><td> ]</td></tr>
|
||||||
|
<tr><td> ^ </td><td> ^</td></tr>
|
||||||
|
<tr><td> _ </td><td> _</td></tr>
|
||||||
|
<tr><td> ` </td><td> `</td></tr>
|
||||||
|
<tr><td> { </td><td> {</td></tr>
|
||||||
|
<tr><td> | </td><td> |</td></tr>
|
||||||
|
<tr><td> } </td><td> }</td></tr>
|
||||||
|
<tr><td> ~ </td><td> ~</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<P>Note that JSTL's {@code <c:out>} escapes <em>only the first
|
||||||
|
five</em> of the above characters.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static String forHTML(String aText) {
|
||||||
|
final StringBuilder result = new StringBuilder();
|
||||||
|
final StringCharacterIterator iterator = new StringCharacterIterator(aText);
|
||||||
|
char character = iterator.current();
|
||||||
|
while (character != CharacterIterator.DONE) {
|
||||||
|
if (character == '<') {
|
||||||
|
result.append("<");
|
||||||
|
} else if (character == '>') {
|
||||||
|
result.append(">");
|
||||||
|
} else if (character == '&') {
|
||||||
|
result.append("&");
|
||||||
|
} else if (character == '\"') {
|
||||||
|
result.append(""");
|
||||||
|
} else if (character == '\t') {
|
||||||
|
addCharEntity(9, result);
|
||||||
|
} else if (character == '!') {
|
||||||
|
addCharEntity(33, result);
|
||||||
|
} else if (character == '#') {
|
||||||
|
addCharEntity(35, result);
|
||||||
|
} else if (character == '$') {
|
||||||
|
addCharEntity(36, result);
|
||||||
|
} else if (character == '%') {
|
||||||
|
addCharEntity(37, result);
|
||||||
|
} else if (character == '\'') {
|
||||||
|
addCharEntity(39, result);
|
||||||
|
} else if (character == '(') {
|
||||||
|
addCharEntity(40, result);
|
||||||
|
} else if (character == ')') {
|
||||||
|
addCharEntity(41, result);
|
||||||
|
} else if (character == '*') {
|
||||||
|
addCharEntity(42, result);
|
||||||
|
} else if (character == '+') {
|
||||||
|
addCharEntity(43, result);
|
||||||
|
} else if (character == ',') {
|
||||||
|
addCharEntity(44, result);
|
||||||
|
} else if (character == '-') {
|
||||||
|
addCharEntity(45, result);
|
||||||
|
} else if (character == '.') {
|
||||||
|
addCharEntity(46, result);
|
||||||
|
} else if (character == '/') {
|
||||||
|
addCharEntity(47, result);
|
||||||
|
} else if (character == ':') {
|
||||||
|
addCharEntity(58, result);
|
||||||
|
} else if (character == ';') {
|
||||||
|
addCharEntity(59, result);
|
||||||
|
} else if (character == '=') {
|
||||||
|
addCharEntity(61, result);
|
||||||
|
} else if (character == '?') {
|
||||||
|
addCharEntity(63, result);
|
||||||
|
} else if (character == '@') {
|
||||||
|
addCharEntity(64, result);
|
||||||
|
} else if (character == '[') {
|
||||||
|
addCharEntity(91, result);
|
||||||
|
} else if (character == '\\') {
|
||||||
|
addCharEntity(92, result);
|
||||||
|
} else if (character == ']') {
|
||||||
|
addCharEntity(93, result);
|
||||||
|
} else if (character == '^') {
|
||||||
|
addCharEntity(94, result);
|
||||||
|
} else if (character == '_') {
|
||||||
|
addCharEntity(95, result);
|
||||||
|
} else if (character == '`') {
|
||||||
|
addCharEntity(96, result);
|
||||||
|
} else if (character == '{') {
|
||||||
|
addCharEntity(123, result);
|
||||||
|
} else if (character == '|') {
|
||||||
|
addCharEntity(124, result);
|
||||||
|
} else if (character == '}') {
|
||||||
|
addCharEntity(125, result);
|
||||||
|
} else if (character == '~') {
|
||||||
|
addCharEntity(126, result);
|
||||||
|
} else {
|
||||||
|
// the char is not a special one
|
||||||
|
// add it to the result as is
|
||||||
|
result.append(character);
|
||||||
|
}
|
||||||
|
character = iterator.next();
|
||||||
|
}
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Escape all ampersand characters in a URL.
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* Replaces all <tt>'&'</tt> characters with <tt>'&'</tt>.
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* An ampersand character may appear in the query string of a URL. The
|
||||||
|
* ampersand character is indeed valid in a URL.
|
||||||
|
* <em>However, URLs usually appear as an <tt>HREF</tt> attribute, and such
|
||||||
|
* attributes have the additional constraint that ampersands must be
|
||||||
|
* escaped.</em>
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* The JSTL <c:url> tag does indeed perform proper URL encoding of query
|
||||||
|
* parameters. But it does not, in general, produce text which is valid as
|
||||||
|
* an <tt>HREF</tt> attribute, simply because it does not escape the
|
||||||
|
* ampersand character. This is a nuisance when multiple query parameters
|
||||||
|
* appear in the URL, since it requires a little extra work.
|
||||||
|
*/
|
||||||
|
public static String forHrefAmpersand(String aURL) {
|
||||||
|
return aURL.replace("&", "&");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String forQuerySpace(String aURL) {
|
||||||
|
return aURL.replace(" ", "\u0020");
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Synonym for <tt>URLEncoder.encode(String, "UTF-8")</tt>.
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* Used to ensure that HTTP query strings are in proper form, by escaping
|
||||||
|
* special characters such as spaces.
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* It is important to note that if a query string appears in an
|
||||||
|
* <tt>HREF</tt> attribute, then there are two issues - ensuring the query
|
||||||
|
* string is valid HTTP (it is URL-encoded), and ensuring it is valid HTML
|
||||||
|
* (ensuring the ampersand is escaped).
|
||||||
|
*/
|
||||||
|
public static String forURL(String aURLFragment) {
|
||||||
|
String result = null;
|
||||||
|
try {
|
||||||
|
result = URLEncoder.encode(aURLFragment, "UTF-8");
|
||||||
|
} catch (UnsupportedEncodingException ex) {
|
||||||
|
throw new RuntimeException("UTF-8 not supported", ex);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addCharEntity(Integer aIdx, StringBuilder aBuilder) {
|
||||||
|
String padding = "";
|
||||||
|
if (aIdx <= 9) {
|
||||||
|
padding = "00";
|
||||||
|
} else if (aIdx <= 99) {
|
||||||
|
padding = "0";
|
||||||
|
} else {
|
||||||
|
// no prefix
|
||||||
|
}
|
||||||
|
String number = padding + aIdx.toString();
|
||||||
|
aBuilder.append("&#" + number + ";");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,7 +26,7 @@ public class VeraHome {
|
|||||||
Iterator<NamedIP> theList = bridgeSettings.getVeraAddress().getDevices().iterator();
|
Iterator<NamedIP> theList = bridgeSettings.getVeraAddress().getDevices().iterator();
|
||||||
while(theList.hasNext()) {
|
while(theList.hasNext()) {
|
||||||
NamedIP aVera = theList.next();
|
NamedIP aVera = theList.next();
|
||||||
veras.put(aVera.getName(), new VeraInfo(aVera, bridgeSettings.isValidVera()));
|
veras.put(aVera.getName(), new VeraInfo(aVera));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,19 +28,15 @@ public class VeraInfo {
|
|||||||
private HttpClient httpClient;
|
private HttpClient httpClient;
|
||||||
private static final String SDATA_REQUEST = ":3480/data_request?id=sdata&output_format=json";
|
private static final String SDATA_REQUEST = ":3480/data_request?id=sdata&output_format=json";
|
||||||
private NamedIP veraAddress;
|
private NamedIP veraAddress;
|
||||||
private Boolean validVera;
|
|
||||||
|
|
||||||
public VeraInfo(NamedIP addressName, Boolean isValidVera) {
|
public VeraInfo(NamedIP addressName) {
|
||||||
super();
|
super();
|
||||||
httpClient = HttpClients.createDefault();
|
httpClient = HttpClients.createDefault();
|
||||||
veraAddress = addressName;
|
veraAddress = addressName;
|
||||||
validVera = isValidVera;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Sdata getSdata() {
|
public Sdata getSdata() {
|
||||||
Sdata theSdata = null;
|
Sdata theSdata = null;
|
||||||
if(!validVera)
|
|
||||||
return theSdata;
|
|
||||||
|
|
||||||
String theUrl = "http://" + veraAddress.getIp() + SDATA_REQUEST;
|
String theUrl = "http://" + veraAddress.getIp() + SDATA_REQUEST;
|
||||||
String theData;
|
String theData;
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ app.config(function ($routeProvider) {
|
|||||||
}).when('/nest', {
|
}).when('/nest', {
|
||||||
templateUrl: 'views/nestactions.html',
|
templateUrl: 'views/nestactions.html',
|
||||||
controller: 'NestController'
|
controller: 'NestController'
|
||||||
|
}).when('/huedevices', {
|
||||||
|
templateUrl: 'views/huedevice.html',
|
||||||
|
controller: 'HueController'
|
||||||
}).otherwise({
|
}).otherwise({
|
||||||
templateUrl: 'views/configuration.html',
|
templateUrl: 'views/configuration.html',
|
||||||
controller: 'ViewingController'
|
controller: 'ViewingController'
|
||||||
@@ -44,12 +47,16 @@ app.run( function (bridgeService) {
|
|||||||
|
|
||||||
app.service('bridgeService', function ($http, $window, ngToast) {
|
app.service('bridgeService', function ($http, $window, ngToast) {
|
||||||
var self = this;
|
var self = this;
|
||||||
this.state = {base: window.location.origin + "/api/devices", bridgelocation: window.location.origin, systemsbase: window.location.origin + "/system", huebase: window.location.origin + "/api", configs: [], backups: [], devices: [], device: [], type: "", settings: [], myToastMsg: [], logMsgs: [], loggerInfo: [], olddevicename: "", logShowAll: false, isInControl: false, showVera: false, showHarmony: false, showNest: false, habridgeversion: ""};
|
this.state = {base: window.location.origin + "/api/devices", bridgelocation: window.location.origin, systemsbase: window.location.origin + "/system", huebase: window.location.origin + "/api", configs: [], backups: [], devices: [], device: [], mapandid: [], type: "", settings: [], myToastMsg: [], logMsgs: [], loggerInfo: [], olddevicename: "", logShowAll: false, isInControl: false, showVera: false, showHarmony: false, showNest: false, showHue: false, habridgeversion: ""};
|
||||||
|
|
||||||
this.displayWarn = function(errorTitle, error) {
|
this.displayWarn = function(errorTitle, error) {
|
||||||
var toastContent = errorTitle;
|
var toastContent = errorTitle;
|
||||||
if(error != null && typeof(error) != 'undefined')
|
if(error != null && typeof(error) != 'undefined') {
|
||||||
toastContent = toastContent + " " + error.data.message + " with status: " + error.statusText + " - " + error.status;
|
if(error.data != null)
|
||||||
|
toastContent = toastContent + " " + error.data.message + " with status: " + error.statusText + " - " + error.status;
|
||||||
|
else
|
||||||
|
toastContent = error;
|
||||||
|
}
|
||||||
ngToast.create({
|
ngToast.create({
|
||||||
className: "warning",
|
className: "warning",
|
||||||
dismissButton: true,
|
dismissButton: true,
|
||||||
@@ -94,6 +101,8 @@ app.service('bridgeService', function ($http, $window, ngToast) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.clearDevice = function () {
|
this.clearDevice = function () {
|
||||||
|
if(self.state.device == null)
|
||||||
|
self.state.device = [];
|
||||||
self.state.device.id = "";
|
self.state.device.id = "";
|
||||||
self.state.device.mapType = null;
|
self.state.device.mapType = null;
|
||||||
self.state.device.mapId = null;
|
self.state.device.mapId = null;
|
||||||
@@ -103,6 +112,7 @@ app.service('bridgeService', function ($http, $window, ngToast) {
|
|||||||
self.state.device.deviceType = "custom";
|
self.state.device.deviceType = "custom";
|
||||||
self.state.device.targetDevice = null;
|
self.state.device.targetDevice = null;
|
||||||
self.state.device.offUrl = "";
|
self.state.device.offUrl = "";
|
||||||
|
self.state.device.headers = null;
|
||||||
self.state.device.httpVerb = null;
|
self.state.device.httpVerb = null;
|
||||||
self.state.device.contentType = null;
|
self.state.device.contentType = null;
|
||||||
self.state.device.contentBody = null;
|
self.state.device.contentBody = null;
|
||||||
@@ -140,6 +150,11 @@ app.service('bridgeService', function ($http, $window, ngToast) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.updateShowHue = function () {
|
||||||
|
this.state.showHue = self.state.settings.hueconfigured;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.loadBridgeSettings = function () {
|
this.loadBridgeSettings = function () {
|
||||||
return $http.get(this.state.systemsbase + "/settings").then(
|
return $http.get(this.state.systemsbase + "/settings").then(
|
||||||
function (response) {
|
function (response) {
|
||||||
@@ -147,6 +162,7 @@ app.service('bridgeService', function ($http, $window, ngToast) {
|
|||||||
self.updateShowVera();
|
self.updateShowVera();
|
||||||
self.updateShowHarmony();
|
self.updateShowHarmony();
|
||||||
self.updateShowNest();
|
self.updateShowNest();
|
||||||
|
self.updateShowHue();
|
||||||
},
|
},
|
||||||
function (error) {
|
function (error) {
|
||||||
self.displayWarn("Load Bridge Settings Error: ", error);
|
self.displayWarn("Load Bridge Settings Error: ", error);
|
||||||
@@ -211,6 +227,19 @@ app.service('bridgeService', function ($http, $window, ngToast) {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.viewHueDevices = function () {
|
||||||
|
if(!this.state.showHue)
|
||||||
|
return;
|
||||||
|
return $http.get(this.state.base + "/hue/devices").then(
|
||||||
|
function (response) {
|
||||||
|
self.state.huedevices = response.data;
|
||||||
|
},
|
||||||
|
function (error) {
|
||||||
|
self.displayWarn("Get Hue Items Error: ", error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
this.viewVeraDevices = function () {
|
this.viewVeraDevices = function () {
|
||||||
if(!this.state.showVera)
|
if(!this.state.showVera)
|
||||||
return;
|
return;
|
||||||
@@ -295,6 +324,7 @@ app.service('bridgeService', function ($http, $window, ngToast) {
|
|||||||
this.bulkAddDevice = function (devices) {
|
this.bulkAddDevice = function (devices) {
|
||||||
return $http.post(this.state.base, devices).then(
|
return $http.post(this.state.base, devices).then(
|
||||||
function (response) {
|
function (response) {
|
||||||
|
self.displaySuccess("Bulk device add successful.");
|
||||||
},
|
},
|
||||||
function (error) {
|
function (error) {
|
||||||
self.displayWarn("Bulk Add new Device Error: ", error);
|
self.displayWarn("Bulk Add new Device Error: ", error);
|
||||||
@@ -570,6 +600,22 @@ app.controller('SystemController', function ($scope, $location, $http, $window,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
$scope.addHuetoSettings = function (newhuename, newhueip) {
|
||||||
|
if($scope.bridge.settings.hueaddress == null) {
|
||||||
|
$scope.bridge.settings.hueaddress = { devices: [] };
|
||||||
|
}
|
||||||
|
var newhue = {name: newhuename, ip: newhueip }
|
||||||
|
$scope.bridge.settings.hueaddress.devices.push(newhue);
|
||||||
|
$scope.newhuename = null;
|
||||||
|
$scope.newhueip = null;
|
||||||
|
};
|
||||||
|
$scope.removeHuetoSettings = function (huename, hueip) {
|
||||||
|
for(var i = $scope.bridge.settings.hueaddress.devices.length - 1; i >= 0; i--) {
|
||||||
|
if($scope.bridge.settings.hueaddress.devices[i].name === huename && $scope.bridge.settings.hueaddress.devices[i].ip === hueip) {
|
||||||
|
$scope.bridge.settings.hueaddress.devices.splice(i, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
$scope.bridgeReinit = function () {
|
$scope.bridgeReinit = function () {
|
||||||
$scope.isInControl = false;
|
$scope.isInControl = false;
|
||||||
bridgeService.reinit();
|
bridgeService.reinit();
|
||||||
@@ -581,10 +627,6 @@ app.controller('SystemController', function ($scope, $location, $http, $window,
|
|||||||
$scope.saveSettings = function() {
|
$scope.saveSettings = function() {
|
||||||
bridgeService.saveSettings();
|
bridgeService.saveSettings();
|
||||||
};
|
};
|
||||||
$scope.setBridgeUrl = function (url) {
|
|
||||||
bridgeService.state.base = url;
|
|
||||||
bridgeService.viewDevices();
|
|
||||||
};
|
|
||||||
$scope.goBridgeUrl = function (url) {
|
$scope.goBridgeUrl = function (url) {
|
||||||
window.open(url, "_blank");
|
window.open(url, "_blank");
|
||||||
};
|
};
|
||||||
@@ -662,13 +704,15 @@ app.controller('ViewingController', function ($scope, $location, $http, $window,
|
|||||||
var dialogNeeded = false;
|
var dialogNeeded = false;
|
||||||
if((type == "on" && (bridgeService.aContainsB(device.onUrl, "${intensity.byte}") ||
|
if((type == "on" && (bridgeService.aContainsB(device.onUrl, "${intensity.byte}") ||
|
||||||
bridgeService.aContainsB(device.onUrl, "${intensity.percent}") ||
|
bridgeService.aContainsB(device.onUrl, "${intensity.percent}") ||
|
||||||
bridgeService.aContainsB(device.onUrl, "${intensity.math("))) ||
|
bridgeService.aContainsB(device.onUrl, "${intensity.math(")) ||
|
||||||
(type == "off" && (bridgeService.aContainsB(device.offUrl, "${intensity.byte}") ||
|
(type == "off" && (bridgeService.aContainsB(device.offUrl, "${intensity.byte}") ||
|
||||||
bridgeService.aContainsB(device.offUrl, "${intensity.percent}") ||
|
bridgeService.aContainsB(device.offUrl, "${intensity.percent}") ||
|
||||||
bridgeService.aContainsB(device.offUrl, "${intensity.math("))) ||
|
bridgeService.aContainsB(device.offUrl, "${intensity.math("))) ||
|
||||||
(type == "dim" && (bridgeService.aContainsB(device.dimUrl, "${intensity.byte}") ||
|
(type == "dim" && (bridgeService.aContainsB(device.dimUrl, "${intensity.byte}") ||
|
||||||
bridgeService.aContainsB(device.dimUrl, "${intensity.percent}") ||
|
bridgeService.aContainsB(device.dimUrl, "${intensity.percent}") ||
|
||||||
bridgeService.aContainsB(device.dimUrl, "${intensity.math(")))) {
|
bridgeService.aContainsB(device.dimUrl, "${intensity.math(") ||
|
||||||
|
bridgeService.aContainsB(device.deviceType, "passthru") ||
|
||||||
|
bridgeService.aContainsB(device.mapType, "hueDevice"))))) {
|
||||||
$scope.bridge.device = device;
|
$scope.bridge.device = device;
|
||||||
$scope.bridge.type = type;
|
$scope.bridge.type = type;
|
||||||
ngDialog.open({
|
ngDialog.open({
|
||||||
@@ -681,7 +725,12 @@ app.controller('ViewingController', function ($scope, $location, $http, $window,
|
|||||||
bridgeService.testUrl(device, type);
|
bridgeService.testUrl(device, type);
|
||||||
};
|
};
|
||||||
$scope.deleteDevice = function (device) {
|
$scope.deleteDevice = function (device) {
|
||||||
bridgeService.deleteDevice(device.id);
|
$scope.bridge.device = device;
|
||||||
|
ngDialog.open({
|
||||||
|
template: 'deleteDialog',
|
||||||
|
controller: 'DeleteDialogCtrl',
|
||||||
|
className: 'ngdialog-theme-default'
|
||||||
|
});
|
||||||
};
|
};
|
||||||
$scope.editDevice = function (device) {
|
$scope.editDevice = function (device) {
|
||||||
bridgeService.editDevice(device);
|
bridgeService.editDevice(device);
|
||||||
@@ -746,7 +795,36 @@ app.controller('ValueDialogCtrl', function ($scope, bridgeService, ngDialog) {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
app.controller('VeraController', function ($scope, $location, $http, bridgeService) {
|
app.controller('DeleteDialogCtrl', function ($scope, bridgeService, ngDialog) {
|
||||||
|
$scope.bridge = bridgeService.state;
|
||||||
|
$scope.device = $scope.bridge.device;
|
||||||
|
$scope.deleteDevice = function (device) {
|
||||||
|
ngDialog.close('ngdialog1');
|
||||||
|
bridgeService.deleteDevice(device.id);
|
||||||
|
bridgeService.viewDevices();
|
||||||
|
$scope.bridge.device = null;
|
||||||
|
$scope.bridge.type = "";
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
app.controller('DeleteMapandIdDialogCtrl', function ($scope, bridgeService, ngDialog) {
|
||||||
|
$scope.bridge = bridgeService.state;
|
||||||
|
$scope.mapandid = $scope.bridge.mapandid;
|
||||||
|
$scope.deleteMapandId = function (mapandid) {
|
||||||
|
ngDialog.close('ngdialog1');
|
||||||
|
bridgeService.deleteDeviceByMapId(mapandid.id, mapandid.mapType);
|
||||||
|
bridgeService.viewDevices();
|
||||||
|
bridgeService.viewVeraDevices();
|
||||||
|
bridgeService.viewVeraScenes();
|
||||||
|
bridgeService.viewHarmonyActivities();
|
||||||
|
bridgeService.viewHarmonyDevices();
|
||||||
|
bridgeService.viewNestItems();
|
||||||
|
bridgeService.viewHueDevices();
|
||||||
|
$scope.bridge.mapandid = null;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
app.controller('VeraController', function ($scope, $location, $http, bridgeService, ngDialog) {
|
||||||
$scope.bridge = bridgeService.state;
|
$scope.bridge = bridgeService.state;
|
||||||
$scope.device = $scope.bridge.device;
|
$scope.device = $scope.bridge.device;
|
||||||
$scope.device_dim_control = "";
|
$scope.device_dim_control = "";
|
||||||
@@ -836,6 +914,7 @@ app.controller('VeraController', function ($scope, $location, $http, bridgeServi
|
|||||||
targetDevice: $scope.device.targetDevice,
|
targetDevice: $scope.device.targetDevice,
|
||||||
onUrl: $scope.device.onUrl,
|
onUrl: $scope.device.onUrl,
|
||||||
offUrl: $scope.device.offUrl,
|
offUrl: $scope.device.offUrl,
|
||||||
|
headers: $scope.device.headers,
|
||||||
httpVerb: $scope.device.httpVerb,
|
httpVerb: $scope.device.httpVerb,
|
||||||
contentType: $scope.device.contentType,
|
contentType: $scope.device.contentType,
|
||||||
contentBody: $scope.device.contentBody,
|
contentBody: $scope.device.contentBody,
|
||||||
@@ -875,15 +954,17 @@ app.controller('VeraController', function ($scope, $location, $http, bridgeServi
|
|||||||
};
|
};
|
||||||
|
|
||||||
$scope.deleteDeviceByMapId = function (id, mapType) {
|
$scope.deleteDeviceByMapId = function (id, mapType) {
|
||||||
bridgeService.deleteDeviceByMapId(id, mapType);
|
$scope.bridge.mapandid = { id, mapType };
|
||||||
bridgeService.viewDevices();
|
ngDialog.open({
|
||||||
bridgeService.viewVeraDevices();
|
template: 'deleteMapandIdDialog',
|
||||||
bridgeService.viewVeraScenes();
|
controller: 'DeleteMapandIdDialogCtrl',
|
||||||
|
className: 'ngdialog-theme-default'
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
app.controller('HarmonyController', function ($scope, $location, $http, bridgeService) {
|
app.controller('HarmonyController', function ($scope, $location, $http, bridgeService, ngDialog) {
|
||||||
$scope.bridge = bridgeService.state;
|
$scope.bridge = bridgeService.state;
|
||||||
$scope.device = $scope.bridge.device;
|
$scope.device = $scope.bridge.device;
|
||||||
bridgeService.viewHarmonyActivities();
|
bridgeService.viewHarmonyActivities();
|
||||||
@@ -952,15 +1033,17 @@ app.controller('HarmonyController', function ($scope, $location, $http, bridgeSe
|
|||||||
};
|
};
|
||||||
|
|
||||||
$scope.deleteDeviceByMapId = function (id, mapType) {
|
$scope.deleteDeviceByMapId = function (id, mapType) {
|
||||||
bridgeService.deleteDeviceByMapId(id, mapType);
|
$scope.bridge.mapandid = { id, mapType };
|
||||||
bridgeService.viewDevices();
|
ngDialog.open({
|
||||||
bridgeService.viewHarmonyActivities();
|
template: 'deleteMapandIdDialog',
|
||||||
bridgeService.viewHarmonyDevices();
|
controller: 'DeleteMapandIdDialogCtrl',
|
||||||
|
className: 'ngdialog-theme-default'
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
app.controller('NestController', function ($scope, $location, $http, bridgeService) {
|
app.controller('NestController', function ($scope, $location, $http, bridgeService, ngDialog) {
|
||||||
$scope.bridge = bridgeService.state;
|
$scope.bridge = bridgeService.state;
|
||||||
$scope.device = $scope.bridge.device;
|
$scope.device = $scope.bridge.device;
|
||||||
bridgeService.viewNestItems();
|
bridgeService.viewNestItems();
|
||||||
@@ -1072,9 +1155,116 @@ app.controller('NestController', function ($scope, $location, $http, bridgeServi
|
|||||||
};
|
};
|
||||||
|
|
||||||
$scope.deleteDeviceByMapId = function (id, mapType) {
|
$scope.deleteDeviceByMapId = function (id, mapType) {
|
||||||
bridgeService.deleteDeviceByMapId(id, mapType);
|
$scope.bridge.mapandid = { id, mapType };
|
||||||
|
ngDialog.open({
|
||||||
|
template: 'deleteMapandIdDialog',
|
||||||
|
controller: 'DeleteMapandIdDialogCtrl',
|
||||||
|
className: 'ngdialog-theme-default'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
app.controller('HueController', function ($scope, $location, $http, bridgeService, ngDialog) {
|
||||||
|
$scope.bridge = bridgeService.state;
|
||||||
|
$scope.device = $scope.bridge.device;
|
||||||
|
$scope.bulk = { devices: [] };
|
||||||
|
bridgeService.viewHueDevices();
|
||||||
|
$scope.imgButtonsUrl = "glyphicon glyphicon-plus";
|
||||||
|
$scope.buttonsVisible = false;
|
||||||
|
|
||||||
|
$scope.clearDevice = function () {
|
||||||
|
bridgeService.clearDevice();
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.buildDeviceUrls = function (huedevice) {
|
||||||
|
bridgeService.clearDevice();
|
||||||
|
if($scope.device == null)
|
||||||
|
$scope.device = $scope.bridge.device;
|
||||||
|
$scope.device.deviceType = "passthru";
|
||||||
|
$scope.device.name = huedevice.device.name;
|
||||||
|
$scope.device.targetDevice = huedevice.huename;
|
||||||
|
$scope.device.contentType = "application/json";
|
||||||
|
$scope.device.mapType = "hueDevice";
|
||||||
|
$scope.device.mapId = huedevice.device.uniqueid;
|
||||||
|
$scope.device.onUrl = "{\"ipAddress\":\"" + huedevice.hueaddress + "\",\"deviceId\":\"" + huedevice.huedeviceid +"\"}";
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.addDevice = function () {
|
||||||
|
if($scope.device.name == "" && $scope.device.onUrl == "")
|
||||||
|
return;
|
||||||
|
bridgeService.addDevice($scope.device).then(
|
||||||
|
function () {
|
||||||
|
$scope.clearDevice();
|
||||||
|
bridgeService.viewDevices();
|
||||||
|
bridgeService.viewHueDevices();
|
||||||
|
},
|
||||||
|
function (error) {
|
||||||
|
bridgeService.displayWarn("Error adding device: " + $scope.device.name, error)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.bulkAddDevices = function() {
|
||||||
|
var devicesList = [];
|
||||||
|
for(var i = 0; i < $scope.bulk.devices.length; i++) {
|
||||||
|
for(var x = 0; x < bridgeService.state.huedevices.length; x++) {
|
||||||
|
if(bridgeService.state.huedevices[x].device.uniqueid == $scope.bulk.devices[i]) {
|
||||||
|
$scope.buildDeviceUrls(bridgeService.state.huedevices[x]);
|
||||||
|
devicesList[i] = {
|
||||||
|
name: $scope.device.name,
|
||||||
|
mapId: $scope.device.mapId,
|
||||||
|
mapType: $scope.device.mapType,
|
||||||
|
deviceType: $scope.device.deviceType,
|
||||||
|
targetDevice: $scope.device.targetDevice,
|
||||||
|
onUrl: $scope.device.onUrl,
|
||||||
|
offUrl: $scope.device.offUrl,
|
||||||
|
headers: $scope.device.headers,
|
||||||
|
httpVerb: $scope.device.httpVerb,
|
||||||
|
contentType: $scope.device.contentType,
|
||||||
|
contentBody: $scope.device.contentBody,
|
||||||
|
contentBodyOff: $scope.device.contentBodyOff
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bridgeService.bulkAddDevice(devicesList);
|
||||||
|
$scope.clearDevice();
|
||||||
bridgeService.viewDevices();
|
bridgeService.viewDevices();
|
||||||
bridgeService.viewNestItems();
|
bridgeService.viewHueDevices();
|
||||||
|
$scope.bulk = { devices: [] };
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.toggleSelection = function toggleSelection(deviceId) {
|
||||||
|
var idx = $scope.bulk.devices.indexOf(deviceId);
|
||||||
|
|
||||||
|
// is currently selected
|
||||||
|
if (idx > -1) {
|
||||||
|
$scope.bulk.devices.splice(idx, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// is newly selected
|
||||||
|
else {
|
||||||
|
$scope.bulk.devices.push(deviceId);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.toggleButtons = function () {
|
||||||
|
$scope.buttonsVisible = !$scope.buttonsVisible;
|
||||||
|
if($scope.buttonsVisible)
|
||||||
|
$scope.imgButtonsUrl = "glyphicon glyphicon-minus";
|
||||||
|
else
|
||||||
|
$scope.imgButtonsUrl = "glyphicon glyphicon-plus";
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.deleteDeviceByMapId = function (id, mapType) {
|
||||||
|
$scope.bridge.mapandid = { id, mapType };
|
||||||
|
ngDialog.open({
|
||||||
|
template: 'deleteMapandIdDialog',
|
||||||
|
controller: 'DeleteMapandIdDialogCtrl',
|
||||||
|
className: 'ngdialog-theme-default'
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
});
|
});
|
||||||
@@ -1282,6 +1472,34 @@ app.filter('unavailableNestItemId', function(bridgeService) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.filter('availableHueDeviceId', function(bridgeService) {
|
||||||
|
return function(input) {
|
||||||
|
var out = [];
|
||||||
|
if(input == null)
|
||||||
|
return out;
|
||||||
|
for (var i = 0; i < input.length; i++) {
|
||||||
|
if(!bridgeService.findDeviceByMapId(input[i].device.uniqueid, input[i].huename, "hueDevice")){
|
||||||
|
out.push(input[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.filter('unavailableHueDeviceId', function(bridgeService) {
|
||||||
|
return function(input) {
|
||||||
|
var out = [];
|
||||||
|
if(input == null)
|
||||||
|
return out;
|
||||||
|
for (var i = 0; i < input.length; i++) {
|
||||||
|
if(bridgeService.findDeviceByMapId(input[i].device.uniqueid, input[i].huename, "hueDevice")){
|
||||||
|
out.push(input[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
app.filter('configuredButtons', function() {
|
app.filter('configuredButtons', function() {
|
||||||
return function(input) {
|
return function(input) {
|
||||||
var out = [];
|
var out = [];
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
||||||
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li>
|
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li>
|
||||||
<li ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
<li ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||||
|
<li ng-if="bridge.showHue" role="presentation"><a href="#/huedevices">Hue Devices</a></li>
|
||||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@@ -102,4 +103,14 @@
|
|||||||
<button type="button" class="ngdialog-button ngdialog-button-primary" ng-click="setValue()">Set</button>
|
<button type="button" class="ngdialog-button ngdialog-button-primary" ng-click="setValue()">Set</button>
|
||||||
</div>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
<script type="text/ng-template" id="deleteDialog">
|
||||||
|
<div class="ngdialog-message">
|
||||||
|
<h2>Device to Delete?</h2>
|
||||||
|
<p>{{device.name}}</p>
|
||||||
|
<p>Are you Sure?</p>
|
||||||
|
</div>
|
||||||
|
<div class="ngdialog-buttons mt">
|
||||||
|
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteDevice(device)">Delete</button>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
||||||
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li>
|
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li>
|
||||||
<li ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
<li ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||||
|
<li ng-if="bridge.showHue" role="presentation"><a href="#/huedevices">Hue Devices</a></li>
|
||||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||||
<li role="presentation" class="active"><a href="#/editdevice">Edit Device</a></li>
|
<li role="presentation" class="active"><a href="#/editdevice">Edit Device</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -43,6 +44,28 @@
|
|||||||
<button class="btn btn-primary" ng-click="copyDevice()">
|
<button class="btn btn-primary" ng-click="copyDevice()">
|
||||||
Add Bridge Device</button>
|
Add Bridge Device</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="device-type">Device Type
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<select name="device-type" id="device-type" ng-model="device.deviceType">
|
||||||
|
<option value="">---Types if needed---</option> <!-- not selected / blank option -->
|
||||||
|
<option value="custom">Custom</option>
|
||||||
|
<option value="UDP">UDP</option>
|
||||||
|
<option value="TCP">TCP</option>
|
||||||
|
<option value="exec">Execute Script/Program</option>
|
||||||
|
<option value="switch">Switch</option>
|
||||||
|
<option value="scene">Scene</option>
|
||||||
|
<option value="activity">Activity</option>
|
||||||
|
<option value="button">Button</option>
|
||||||
|
<option value="thermo">Thermo</option>
|
||||||
|
<option value="passthru">Pass Thru</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label class="col-xs-12 col-sm-2 control-label" for="device-map-type">Map Type
|
<label class="col-xs-12 col-sm-2 control-label" for="device-map-type">Map Type
|
||||||
@@ -57,6 +80,7 @@
|
|||||||
<option value="harmonyButton">Harmony Button</option>
|
<option value="harmonyButton">Harmony Button</option>
|
||||||
<option value="nestHomeAway">Nest Home Status</option>
|
<option value="nestHomeAway">Nest Home Status</option>
|
||||||
<option value="nestThermoSet">Nest Thermostat</option>
|
<option value="nestThermoSet">Nest Thermostat</option>
|
||||||
|
<option value="hueDevice">Hue Device</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-danger" ng-click="clearDevice()">
|
<button class="btn btn-danger" ng-click="clearDevice()">
|
||||||
@@ -105,6 +129,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label"
|
||||||
|
for="device-headers">HTTP Headers </label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<textarea rows="3" class="form-control" id="device-headers"
|
||||||
|
ng-model="device.headers" placeholder="format like: [{"name":"A name","value":"a value"}]"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label class="col-xs-12 col-sm-2 control-label" for="device-http-verb">Http Verb
|
<label class="col-xs-12 col-sm-2 control-label" for="device-http-verb">Http Verb
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
||||||
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li>
|
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li>
|
||||||
<li ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
<li ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||||
|
<li ng-if="bridge.showHue" role="presentation"><a href="#/huedevices">Hue Devices</a></li>
|
||||||
<li role="presentation" class="active"><a href="#/editor">Manual Add</a></li>
|
<li role="presentation" class="active"><a href="#/editor">Manual Add</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@@ -77,7 +78,10 @@
|
|||||||
<h2 class="panel-title">Add a new device</h2>
|
<h2 class="panel-title">Add a new device</h2>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-muted">This area allows you to create any http or udp call to an endpoint. You can use the default GET or select
|
<p class="text-muted">This area allows you to create any http or udp call to an endpoint. You can use the default GET or select
|
||||||
the http verb type below and configure a payload for either on or off methods. Currently, https is not supported.</p>
|
the http verb type below and configure a payload for either on, dim or off methods. Currently, https is not supported. For Execution of
|
||||||
|
a script or program, plese fill in the path. All manually entered calls can use Json notation of array with
|
||||||
|
[{"item":"the payload"},{"item":"another payload"}] to execute multiple entries. Adding the value replacements (${intensity..byte},${intensity.percent},${intensity.math(X*1)})
|
||||||
|
will also work.</p>
|
||||||
<ul class="list-group">
|
<ul class="list-group">
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<form class="form-horizontal">
|
<form class="form-horizontal">
|
||||||
@@ -94,6 +98,22 @@
|
|||||||
Add Bridge Device</button>
|
Add Bridge Device</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="device-type">Device Type
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<select name="device-type" id="device-type" ng-model="device.deviceType">
|
||||||
|
<option value="">---Types if needed---</option> <!-- not selected / blank option -->
|
||||||
|
<option value="custom">Custom</option>
|
||||||
|
<option value="UDP">UDP</option>
|
||||||
|
<option value="TCP">TCP</option>
|
||||||
|
<option value="exec">Execute Script/Program</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
|
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
|
||||||
@@ -129,6 +149,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label"
|
||||||
|
for="device-headers">HTTP Headers </label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<textarea rows="3" class="form-control" id="device-headers"
|
||||||
|
ng-model="device.headers" placeholder="format like: [{"name":"A name","value":"a value"}]"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label class="col-xs-12 col-sm-2 control-label" for="device-http-verb">Http Verb
|
<label class="col-xs-12 col-sm-2 control-label" for="device-http-verb">Http Verb
|
||||||
|
|||||||
@@ -7,10 +7,11 @@
|
|||||||
<li role="presentation" class="active"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
<li role="presentation" class="active"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
||||||
<li role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li>
|
<li role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li>
|
||||||
<li ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
<li ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||||
|
<li ng-if="bridge.showHue" role="presentation"><a href="#/huedevices">Hue Devices</a></li>
|
||||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
<div class="panel panel-default bridgeServer">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h2 class="panel-title">Harmony Activity List</h2>
|
<h2 class="panel-title">Harmony Activity List</h2>
|
||||||
</div>
|
</div>
|
||||||
@@ -38,8 +39,7 @@
|
|||||||
<td>{{harmonyactivity.hub}}</td>
|
<td>{{harmonyactivity.hub}}</td>
|
||||||
<td>
|
<td>
|
||||||
<button class="btn btn-success" type="submit"
|
<button class="btn btn-success" type="submit"
|
||||||
ng-click="buildActivityUrls(harmonyactivity)">Generate
|
ng-click="buildActivityUrls(harmonyactivity)">Generate Bridge Device</button>
|
||||||
Activity URLs</button>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
@@ -75,7 +75,7 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
<div class="panel panel-default bridgeServer">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h2 class="panel-title">Add a Bridge Device for a Harmony Activity</h2>
|
<h2 class="panel-title">Add a Bridge Device for a Harmony Activity</h2>
|
||||||
</div>
|
</div>
|
||||||
@@ -121,3 +121,13 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
<script type="text/ng-template" id="deleteMapandIdDialog">
|
||||||
|
<div class="ngdialog-message">
|
||||||
|
<h2>Device Map and Id?</h2>
|
||||||
|
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
|
||||||
|
<p>Are you Sure?</p>
|
||||||
|
</div>
|
||||||
|
<div class="ngdialog-buttons mt">
|
||||||
|
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
|||||||
@@ -7,10 +7,11 @@
|
|||||||
<li role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
<li role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
||||||
<li role="presentation" class="active"><a href="#/harmonydevices">Harmony Devices</a></li>
|
<li role="presentation" class="active"><a href="#/harmonydevices">Harmony Devices</a></li>
|
||||||
<li ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
<li ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||||
|
<li ng-if="bridge.showHue" role="presentation"><a href="#/huedevices">Hue Devices</a></li>
|
||||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
<div class="panel panel-default bridgeServer">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h2 class="panel-title">Harmony Device List</h2>
|
<h2 class="panel-title">Harmony Device List</h2>
|
||||||
</div>
|
</div>
|
||||||
@@ -95,7 +96,7 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
<div class="panel panel-default bridgeServer">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h2 class="panel-title">Add a Bridge Device for Harmony Buttons</h2>
|
<h2 class="panel-title">Add a Bridge Device for Harmony Buttons</h2>
|
||||||
</div>
|
</div>
|
||||||
@@ -141,3 +142,13 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
<script type="text/ng-template" id="deleteMapandIdDialog">
|
||||||
|
<div class="ngdialog-message">
|
||||||
|
<h2>Device Map and Id?</h2>
|
||||||
|
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
|
||||||
|
<p>Are you Sure?</p>
|
||||||
|
</div>
|
||||||
|
<div class="ngdialog-buttons mt">
|
||||||
|
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
|||||||
129
src/main/resources/public/views/huedevice.html
Normal file
129
src/main/resources/public/views/huedevice.html
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
<ul class="nav nav-pills" role="tablist">
|
||||||
|
<li role="presentation"><a href="#">Bridge Devices</a></li>
|
||||||
|
<li role="presentation"><a href="#/system">Bridge Control</a></li>
|
||||||
|
<li role="presentation"><a href="#/logs">Logs</a></li>
|
||||||
|
<li ng-if="bridge.showVera" role="presentation"><a href="#/veradevices">Vera Devices</a></li>
|
||||||
|
<li ng-if="bridge.showVera" role="presentation"><a href="#/verascenes">Vera Scenes</a></li>
|
||||||
|
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
||||||
|
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li>
|
||||||
|
<li ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||||
|
<li role="presentation" class="active"><a href="#/huedevices">Hue Devices</a></li>
|
||||||
|
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="panel panel-default bridgeServer">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h2 class="panel-title">Hue Device List ({{bridge.huedevices.length}})</h2>
|
||||||
|
</div>
|
||||||
|
<ul class="list-group">
|
||||||
|
<li class="list-group-item">
|
||||||
|
<p class="text-muted">For any Hue Device, use the action buttons to generate the device addition information below automatically.
|
||||||
|
Then you can modify the name to anything you want that will be the keyword for Alexa. Click the 'Add Bridge Device' to finish that selection setup.
|
||||||
|
The 'Already Configured Hue Devices' list below will show what is already setup for your Hue.</p>
|
||||||
|
<p>Use the check boxes by the names to use the bulk addition feature. Select your items, then click bulk add below.
|
||||||
|
Your items will be added with on and off or dim and off if selected with the name of the device from the Hue.
|
||||||
|
</p>
|
||||||
|
<scrollable-table watch="bridge.huedevices">
|
||||||
|
<table class="table table-bordered table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Row</th>
|
||||||
|
<th sortable-header col="name">Name</th>
|
||||||
|
<th sortable-header col="id">Id</th>
|
||||||
|
<th sortable-header col="huename">Hue</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr ng-repeat="huedevice in bridge.huedevices | availableHueDeviceId">
|
||||||
|
<td>{{$index+1}}</td>
|
||||||
|
<td><input type="checkbox" name="bulk.devices[]" value="{{huedevice.device.uniqueid}}" ng-checked="bulk.devices.indexOf(huedevice.device.uniqueid) > -1" ng-click="toggleSelection(huedevice.device.uniqueid)"> {{huedevice.device.name}}</td>
|
||||||
|
<td>{{huedevice.device.uniqueid}}</td>
|
||||||
|
<td>{{huedevice.huename}}</td>
|
||||||
|
<td>
|
||||||
|
<button class="btn btn-success" type="submit"
|
||||||
|
ng-click="buildDeviceUrls(huedevice)">Generate Bridge Device</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</scrollable-table>
|
||||||
|
<p>
|
||||||
|
<button class="btn btn-success" type="submit"
|
||||||
|
ng-click="bulkAddDevices()">Bulk Add ({{bulk.devices.length}})</button>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h2 class="panel-title">Already Configured Hue Devices <a ng-click="toggleButtons()"><span class={{imgButtonsUrl}} aria-hidden="true"></span></a></a></h2>
|
||||||
|
</div>
|
||||||
|
<ul ng-if="buttonsVisible" class="list-group">
|
||||||
|
<li class="list-group-item">
|
||||||
|
<scrollable-table watch="bridge.huedevices">
|
||||||
|
<table class="table table-bordered table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Row</th>
|
||||||
|
<th sortable-header col="name">Name</th>
|
||||||
|
<th sortable-header col="id">Id</th>
|
||||||
|
<th sortable-header col="huename">hue</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr ng-repeat="huedevice in bridge.huedevices | unavailableHueDeviceId">
|
||||||
|
<td>{{$index+1}}</td>
|
||||||
|
<td>{{huedevice.device.name}}</td>
|
||||||
|
<td>{{huedevice.device.uniqueid}}</td>
|
||||||
|
<td>{{huedevice.huename}}</td>
|
||||||
|
<td>
|
||||||
|
<button class="btn btn-danger" type="submit"
|
||||||
|
ng-click="deleteDeviceByMapId(huedevice.device.uniqueid, 'hueDevice')">Delete</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</scrollable-table>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="panel panel-default bridgeServer">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h2 class="panel-title">Add Bridge Device for a Hue Device</h2>
|
||||||
|
</div>
|
||||||
|
<ul class="list-group">
|
||||||
|
<li class="list-group-item">
|
||||||
|
<form class="form-horizontal">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<input type="text" class="form-control" id="device-name"
|
||||||
|
ng-model="device.name" placeholder="Device Name">
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary" ng-click="addDevice()">
|
||||||
|
Add Bridge Device</button>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
|
||||||
|
URL </label>
|
||||||
|
|
||||||
|
<div class="col-xs-8 col-sm-7">
|
||||||
|
<textarea rows="3" class="form-control" id="device-on-url"
|
||||||
|
ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-danger" ng-click="clearDevice()">
|
||||||
|
Clear Device</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<script type="text/ng-template" id="deleteMapandIdDialog">
|
||||||
|
<div class="ngdialog-message">
|
||||||
|
<h2>Device Map and Id?</h2>
|
||||||
|
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
|
||||||
|
<p>Are you Sure?</p>
|
||||||
|
</div>
|
||||||
|
<div class="ngdialog-buttons mt">
|
||||||
|
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
||||||
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li>
|
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li>
|
||||||
<li ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
<li ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||||
|
<li ng-if="bridge.showHue" role="presentation"><a href="#/huedevices">Hue Devices</a></li>
|
||||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|||||||
@@ -7,10 +7,11 @@
|
|||||||
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
||||||
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li>
|
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li>
|
||||||
<li role="presentation" class="active"><a href="#/nest">Nest</a></li>
|
<li role="presentation" class="active"><a href="#/nest">Nest</a></li>
|
||||||
|
<li ng-if="bridge.showHue" role="presentation"><a href="#/huedevices">Hue Devices</a></li>
|
||||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
<div class="panel panel-default bridgeServer">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h2 class="panel-title">Nest Items List</h2>
|
<h2 class="panel-title">Nest Items List</h2>
|
||||||
</div>
|
</div>
|
||||||
@@ -96,7 +97,7 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
<div class="panel panel-default bridgeServer">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h2 class="panel-title">Add a Bridge Device for a Nest Item</h2>
|
<h2 class="panel-title">Add a Bridge Device for a Nest Item</h2>
|
||||||
</div>
|
</div>
|
||||||
@@ -142,3 +143,13 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
<script type="text/ng-template" id="deleteMapandIdDialog">
|
||||||
|
<div class="ngdialog-message">
|
||||||
|
<h2>Device Map and Id?</h2>
|
||||||
|
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
|
||||||
|
<p>Are you Sure?</p>
|
||||||
|
</div>
|
||||||
|
<div class="ngdialog-buttons mt">
|
||||||
|
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
||||||
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li>
|
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li>
|
||||||
<li ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
<li ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||||
|
<li ng-if="bridge.showHue" role="presentation"><a href="#/huedevices">Hue Devices</a></li>
|
||||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@@ -26,9 +27,7 @@
|
|||||||
ng-model="bridge.base" placeholder="URL to bridge">
|
ng-model="bridge.base" placeholder="URL to bridge">
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="col-xs-2 col-sm-1 btn btn-primary"
|
<button type="submit" class="col-xs-2 col-sm-1 btn btn-primary"
|
||||||
ng-click="setBridgeUrl(bridge.base)">Load</button>
|
ng-click="goBridgeUrl(bridge.base)">Test</button>
|
||||||
<button type="submit" class="col-xs-2 col-sm-1 btn btn-primary"
|
|
||||||
ng-click="goBridgeUrl(bridge.base)">Go</button>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<form name="form">
|
<form name="form">
|
||||||
@@ -144,9 +143,31 @@
|
|||||||
ng-model="bridge.settings.harmonypwd" placeholder="thepassword"></td>
|
ng-model="bridge.settings.harmonypwd" placeholder="thepassword"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Button Press Sleep Interval (ms)</td>
|
<td>Hue Names and IP Addresses</td>
|
||||||
<td><input id="bridge-settings-buttonsleep" class="form-control" type="number" name="input"
|
<td><table class="table table-bordered table-striped table-hover">
|
||||||
ng-model="bridge.settings.buttonsleep" min="100" max="9999"></td>
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>IP</th>
|
||||||
|
<th>Manage</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tr ng-repeat="hue in bridge.settings.hueaddress.devices">
|
||||||
|
<td>{{hue.name}}</td>
|
||||||
|
<td>{{hue.ip}}</td>
|
||||||
|
<td><button class="btn btn-danger" type="submit"
|
||||||
|
ng-click="removeHuetoSettings(hue.name, hue.ip)">Del</button></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><input id="bridge-settings-next-hue-name" class="form-control" type="text"
|
||||||
|
ng-model="newhuename" placeholder="A Hue"></td>
|
||||||
|
<td><input id="bridge-settings-next-hue-ip" class="form-control" type="text"
|
||||||
|
ng-model="newhueip" placeholder="192.168.1.3"></td>
|
||||||
|
<td><button class="btn btn-success" type="submit"
|
||||||
|
ng-click="addHuetoSettings(newhuename, newhueip)">Add</button></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Nest Username</td>
|
<td>Nest Username</td>
|
||||||
@@ -158,6 +179,16 @@
|
|||||||
<td><input id="bridge-settings-nestpwd" class="form-control" type="password"
|
<td><input id="bridge-settings-nestpwd" class="form-control" type="password"
|
||||||
ng-model="bridge.settings.nestpwd" placeholder="thepassword"></td>
|
ng-model="bridge.settings.nestpwd" placeholder="thepassword"></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Nest Temp Farenheit</td>
|
||||||
|
<td><input type="checkbox" ng-model="bridge.settings.farenheit"
|
||||||
|
ng-true-value=true ng-false-value=false> {{bridge.settings.farenheit}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Button Press/Call Item Loop Sleep Interval (ms)</td>
|
||||||
|
<td><input id="bridge-settings-buttonsleep" class="form-control" type="number" name="input"
|
||||||
|
ng-model="bridge.settings.buttonsleep" min="100" max="9999"></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Log Messages to Buffer</td>
|
<td>Log Messages to Buffer</td>
|
||||||
<td><input id="bridge-settings-numberoflogmessages" class="form-control" type="number"
|
<td><input id="bridge-settings-numberoflogmessages" class="form-control" type="number"
|
||||||
@@ -173,11 +204,6 @@
|
|||||||
<td><input type="checkbox" ng-model="bridge.settings.traceupnp"
|
<td><input type="checkbox" ng-model="bridge.settings.traceupnp"
|
||||||
ng-true-value=true ng-false-value=false> {{bridge.settings.traceupnp}}</td>
|
ng-true-value=true ng-false-value=false> {{bridge.settings.traceupnp}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td>Nest Temp Farenheit</td>
|
|
||||||
<td><input type="checkbox" ng-model="bridge.settings.farenheit"
|
|
||||||
ng-true-value=true ng-false-value=false> {{bridge.settings.farenheit}}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
</table>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,10 +7,11 @@
|
|||||||
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
||||||
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li>
|
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li>
|
||||||
<li ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
<li ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||||
|
<li ng-if="bridge.showHue" role="presentation"><a href="#/huedevices">Hue Devices</a></li>
|
||||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
<div class="panel panel-default bridgeServer">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h2 class="panel-title">Vera Device List ({{bridge.veradevices.length}})</h2>
|
<h2 class="panel-title">Vera Device List ({{bridge.veradevices.length}})</h2>
|
||||||
</div>
|
</div>
|
||||||
@@ -23,7 +24,7 @@
|
|||||||
control you would like to be generated:
|
control you would like to be generated:
|
||||||
<select name="device-dim-control" id="device-dim-control" ng-model="device_dim_control">
|
<select name="device-dim-control" id="device-dim-control" ng-model="device_dim_control">
|
||||||
<option value="">none</option>
|
<option value="">none</option>
|
||||||
<option value="${intensity..byte}">Pass-thru Value</option>
|
<option value="${intensity.byte}">Pass-thru Value</option>
|
||||||
<option value="${intensity.percent}">Percentage</option>
|
<option value="${intensity.percent}">Percentage</option>
|
||||||
<option value="${intensity.math(X*1)}">Custom Math</option>
|
<option value="${intensity.math(X*1)}">Custom Math</option>
|
||||||
</select>
|
</select>
|
||||||
@@ -53,8 +54,7 @@
|
|||||||
<td>{{veradevice.veraname}}</td>
|
<td>{{veradevice.veraname}}</td>
|
||||||
<td>
|
<td>
|
||||||
<button class="btn btn-success" type="submit"
|
<button class="btn btn-success" type="submit"
|
||||||
ng-click="buildDeviceUrls(veradevice, device_dim_control)">Generate
|
ng-click="buildDeviceUrls(veradevice, device_dim_control)">Generate Bridge Device</button>
|
||||||
Device URLs</button>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
@@ -100,7 +100,7 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
<div class="panel panel-default bridgeServer">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h2 class="panel-title">Add Bridge Device for a Vera Device</h2>
|
<h2 class="panel-title">Add Bridge Device for a Vera Device</h2>
|
||||||
</div>
|
</div>
|
||||||
@@ -155,3 +155,13 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
<script type="text/ng-template" id="deleteMapandIdDialog">
|
||||||
|
<div class="ngdialog-message">
|
||||||
|
<h2>Device Map and Id?</h2>
|
||||||
|
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
|
||||||
|
<p>Are you Sure?</p>
|
||||||
|
</div>
|
||||||
|
<div class="ngdialog-buttons mt">
|
||||||
|
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
|||||||
@@ -7,10 +7,11 @@
|
|||||||
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li>
|
||||||
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li>
|
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li>
|
||||||
<li ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
<li ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
|
||||||
|
<li ng-if="bridge.showHue" role="presentation"><a href="#/huedevices">Hue Devices</a></li>
|
||||||
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
<li role="presentation"><a href="#/editor">Manual Add</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
<div class="panel panel-default bridgeServer">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h2 class="panel-title">Vera Scene List</h2>
|
<h2 class="panel-title">Vera Scene List</h2>
|
||||||
</div>
|
</div>
|
||||||
@@ -40,8 +41,7 @@
|
|||||||
<td>{{verascene.veraname}}</td>
|
<td>{{verascene.veraname}}</td>
|
||||||
<td>
|
<td>
|
||||||
<button class="btn btn-success" type="submit"
|
<button class="btn btn-success" type="submit"
|
||||||
ng-click="buildSceneUrls(verascene)">Generate
|
ng-click="buildSceneUrls(verascene)">Generate Bridge Device</button>
|
||||||
Scene URLs</button>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
@@ -81,7 +81,7 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel panel-default bridgeServer" ng-if="!bridge.error">
|
<div class="panel panel-default bridgeServer">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h2 class="panel-title">Add a Bridge Device for a Vera scene</h2>
|
<h2 class="panel-title">Add a Bridge Device for a Vera scene</h2>
|
||||||
</div>
|
</div>
|
||||||
@@ -125,3 +125,13 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
<script type="text/ng-template" id="deleteMapandIdDialog">
|
||||||
|
<div class="ngdialog-message">
|
||||||
|
<h2>Device Map and Id?</h2>
|
||||||
|
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
|
||||||
|
<p>Are you Sure?</p>
|
||||||
|
</div>
|
||||||
|
<div class="ngdialog-buttons mt">
|
||||||
|
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user