Compare commits

..

53 Commits

Author SHA1 Message Date
BWS Systems
5a59747bc9 Merge pull request #141 from bwssytems/hal-integration
Hal integration and other enhancement and fixes
2016-07-19 11:48:49 -05:00
Admin
53ec096c95 Updated version based on enhancement and bug implementations
Fixes #120
Fixes #122
Fixes #123
Fixes #135
Fixes #137
Fixes #138
Fixes #139
2016-07-19 11:42:07 -05:00
Admin
8ccb768391 Updated group 0 handling to be per hue api requirements. 2016-07-15 16:27:53 -05:00
Admin
9d84e2a180 fixed dim addition in bulk add
modified savef button to be active always in bridge settings
2016-07-12 16:26:53 -05:00
Admin
6a5fae583f Updating bridge control to activate save button on list updates. 2016-07-11 16:32:54 -05:00
Admin
8d15d0a0fb Tested api changes 2016-06-09 16:44:11 -05:00
Admin
d4b8b70a83 Added Hue Error Handling objects. Adding whitelsit control. 2016-06-08 16:41:46 -05:00
Admin
a276f97776 Testing api 1.10.0 2016-06-07 16:39:59 -05:00
Admin
9438b25538 Testing upnp response structures. 2016-06-06 16:42:46 -05:00
Admin
6c15ca2c3b Updated the Hue API v 1.11 and tested.
Testing the upnp changes, ongoing.
2016-06-03 16:25:00 -05:00
Admin
39782fa339 Updateing for API V 1.11 and Bridge V2 HUE handling. 2016-06-02 16:51:02 -05:00
Admin
d7e29e2ee5 Finished implementation of HAL calls to the API. Testing next. 2016-05-26 16:06:48 -05:00
Admin
6b4693eaaf Added Home control, Thermostat and other enhancements. 2016-05-25 16:09:29 -05:00
Admin
7f816b03d5 Fixed sizing of scrollable table to be dynamic. Added Appliances,
Theater and Custom devices to HAL interface. Added Select ALL feature
for bulk add screens.
2016-05-24 16:42:05 -05:00
Admin
ed3db4427b Updated view consistency. Fixed HAL bulk add 2016-05-23 16:45:47 -05:00
bwssystems
80ca8c3ca3 updated html pages to reference hal tab 2016-05-21 16:59:03 -05:00
bwssystems
e43473734e Finished draft HAL integration for lights type only 2016-05-21 16:49:12 -05:00
Admin
8a468b8352 First cut at HAL itegration 2016-05-20 16:13:48 -05:00
bwssystems
51ce10cfc7 Fixed build device button in Harmony Device helper tab.
Fixes #116
2016-05-15 12:25:28 -05:00
Admin
b5f7144c9c Update readme with a script construction. 2016-05-11 14:36:58 -05:00
Admin
86a931d383 added exec:// type for loops. updated button maptypeid naming.
Fixes #114
Fixes #115
2016-05-11 12:23:43 -05:00
Admin
3e890721c5 Fixed handling of dim and brigthen requests as they were not setting the
state appropriately for other systems. Fixed handling of data return
from an http call if the entity was empty.

Fixes #102
Fixes #107
2016-05-10 12:29:37 -05:00
Admin
62d1c64a3d Updated entitiy handling in HueMulator http call. 2016-05-06 08:30:37 -05:00
Admin
c025b186cd Updated a comment for the seb server port 2016-05-05 14:13:06 -05:00
Admin
e999c3a969 Update spelling in readme 2016-05-05 10:45:03 -05:00
Admin
351403e611 Fixed success parsing on http to return success. 2016-05-04 14:38:37 -05:00
Admin
c773477a43 Added delete dialog for confirmation. Fixed bug with text in
intensity.byte for vera device tab. Fixed issue with parsing replies for
http requests. Fixed Hue device bulk add. recommit


Fixes #100
Fixes #102
Fixes #104
Fixes #105
2016-05-04 11:45:51 -05:00
BWS Systems
5d1f0ce3b6 update versions in unit file 2016-05-02 15:41:01 -05:00
Admin
7e0fd6c21b Updated the register with hue function to not send a user name when
linking as this has been deprecated by Philips.

Fixes #99
2016-04-29 16:12:52 -05:00
BWS Systems
3bf52f5da0 Updated Readme
Added comment for Hue proxy and using the link button.
2016-04-29 12:54:08 -05:00
BWS Systems
bd856d8f9e Fixed spelling 2016-04-29 12:44:30 -05:00
Admin
73b2be752e Issue with http/https handling trying to token out line. Updated Readme
Fixes #96
Fixes #98
2016-04-29 12:27:15 -05:00
Admin
dda7a7a34a Merge remote-tracking branch 'origin/add-color-args' 2016-04-29 11:26:06 -05:00
Admin
f238e05533 Fixed bug where device state object was dropped from hue api device
response object. This caused devices to appear offline and invalid
response interpretation by the echo.

Fixes #93
2016-04-28 12:12:49 -05:00
Admin
aaaebd0c05 Merged add-color-args branch to master.
Fixes #72
Fixes #81
Fixes #82
Fixes #85
Fixes #87
Fixes #88
Fixes #89
Fixes #90
2016-04-27 14:42:52 -05:00
Admin
9a1924422e Updated Readme 2016-04-27 13:07:49 -05:00
Admin
e446c618ce MAde the generate buttons consistent in the UI. Updated the Readme. 2016-04-27 12:40:54 -05:00
Admin
60d35acff9 update readme for formatting 2016-04-27 09:11:11 -05:00
Admin
c9adab53a9 Updated selections in device add or editor and updated loggin for upnp
listener and updated the readme
2016-04-27 09:08:41 -05:00
Admin
72b6b2027b Finished updating UPNP handling with ports and errors and testing for
new features.

Updateding README
2016-04-26 16:49:26 -05:00
Admin
60239bad82 Finished testing and refactoring for udp/tcp and http 2016-04-26 10:12:36 -05:00
Admin
aecd589308 Finished implementation of headers and tested. Added calls for TCP
request with UDP and also added the value replacement for dimming, this
needs to be tested.
2016-04-25 16:48:59 -05:00
Admin
ee45cee8e3 Fixed error handling in for loops 2016-04-22 14:00:47 -05:00
Admin
21e5dfb338 added multiple command execution. Added commandline Exec. NEeds testing 2016-04-22 13:59:12 -05:00
Admin
b73a4cd666 Finished testing and updating HUE passthru handling 2016-04-22 10:58:54 -05:00
Admin
05418fdda1 Updated passthru after more testing 2016-04-21 15:41:06 -05:00
Admin
a717fd7c68 Add new classes. 2016-04-20 16:44:39 -05:00
Admin
8408d7350e More testing on HUE passthru. 2016-04-20 16:44:02 -05:00
Admin
3ba8f56db2 Completed Hue passthru 2016-04-18 16:41:15 -05:00
Admin
7a0946e3b7 Continue adding HUE pass thru. 2016-04-15 16:30:34 -05:00
Admin
50c9369d71 Added config override for server port. Updated Readme. Continued
enhancements to pass color to a real hue.
2016-04-14 17:12:06 -05:00
Admin
6c2a34f507 Updated code for collor passing. 2016-04-04 16:36:05 -05:00
Admin
ee2c105040 Started implementation 2016-04-01 16:33:55 -05:00
55 changed files with 5349 additions and 1544 deletions

347
README.md

File diff suppressed because one or more lines are too long

14
pom.xml
View File

@@ -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.3</version> <version>3.0.0</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>HA Bridge</name> <name>HA Bridge</name>
@@ -89,17 +89,7 @@
<dependency> <dependency>
<groupId>com.google.code.gson</groupId> <groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId> <artifactId>gson</artifactId>
<version>2.2.4</version> <version>2.6.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.6.0</version>
</dependency>
<dependency>
<groupId>com.cedarsoftware</groupId>
<artifactId>json-io</artifactId>
<version>4.1.6</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.java.dev.eval</groupId> <groupId>net.java.dev.eval</groupId>

View File

@@ -20,6 +20,7 @@ import com.bwssystems.util.JsonTransformer;
import com.google.gson.Gson; import com.google.gson.Gson;
public class BridgeSettings extends BackupHandler { public class BridgeSettings extends BackupHandler {
private static final Logger log = LoggerFactory.getLogger(BridgeSettings.class);
private BridgeSettingsDescriptor theBridgeSettings; private BridgeSettingsDescriptor theBridgeSettings;
private BridgeControlDescriptor bridgeControl; private BridgeControlDescriptor bridgeControl;
@@ -35,7 +36,6 @@ public class BridgeSettings extends BackupHandler {
return theBridgeSettings; return theBridgeSettings;
} }
public void buildSettings() { public void buildSettings() {
Logger log = LoggerFactory.getLogger(BridgeSettings.class);
InetAddress address = null; InetAddress address = null;
String addressString = null; String addressString = null;
String theVeraAddress = null; String theVeraAddress = null;
@@ -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);
@@ -146,14 +146,24 @@ public class BridgeSettings extends BackupHandler {
theBridgeSettings.setUpnpDeviceDb(Configuration.DEVICE_DB_DIRECTORY); theBridgeSettings.setUpnpDeviceDb(Configuration.DEVICE_DB_DIRECTORY);
if(theBridgeSettings.getNumberoflogmessages() == null) if(theBridgeSettings.getNumberoflogmessages() == null)
theBridgeSettings.setNumberoflogmessages(Configuration.NUMBER_OF_LOG_MESSAGES); theBridgeSettings.setNumberoflogmessages(new Integer(Configuration.NUMBER_OF_LOG_MESSAGES));
if(theBridgeSettings.getButtonsleep() <= 0) if(theBridgeSettings.getNumberoflogmessages() <= 0)
theBridgeSettings.setNumberoflogmessages(new Integer(Configuration.NUMBER_OF_LOG_MESSAGES));
if(theBridgeSettings.getButtonsleep() == null)
theBridgeSettings.setButtonsleep(Integer.parseInt(Configuration.DEFAULT_BUTTON_SLEEP));
if(theBridgeSettings.getButtonsleep() < 0)
theBridgeSettings.setButtonsleep(Integer.parseInt(Configuration.DEFAULT_BUTTON_SLEEP)); theBridgeSettings.setButtonsleep(Integer.parseInt(Configuration.DEFAULT_BUTTON_SLEEP));
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());
theBridgeSettings.setHalconfigured(theBridgeSettings.isValidHal());
if(serverPortOverride != null)
theBridgeSettings.setServerPort(serverPortOverride);
setupParams(Paths.get(theBridgeSettings.getConfigfile()), ".cfgbk", "habridge.config-"); setupParams(Paths.get(theBridgeSettings.getConfigfile()), ".cfgbk", "habridge.config-");
} }
@@ -168,29 +178,17 @@ public class BridgeSettings extends BackupHandler {
private void _loadConfig(Path aPath) { private void _loadConfig(Path aPath) {
String jsonContent = configReader(aPath); String jsonContent = configReader(aPath);
BridgeSettingsDescriptor aBridgeSettings = new Gson().fromJson(jsonContent, BridgeSettingsDescriptor.class); try {
theBridgeSettings.setButtonsleep(aBridgeSettings.getButtonsleep()); theBridgeSettings = new Gson().fromJson(jsonContent, BridgeSettingsDescriptor.class);
theBridgeSettings.setUpnpConfigAddress(aBridgeSettings.getUpnpConfigAddress()); } catch (Exception e) {
theBridgeSettings.setServerPort(aBridgeSettings.getServerPort()); log.warn("Issue loading values from file: " + aPath.toUri().toString() + ", Gson convert failed.");
theBridgeSettings.setUpnpResponsePort(aBridgeSettings.getUpnpResponsePort()); theBridgeSettings = new BridgeSettingsDescriptor();
theBridgeSettings.setUpnpDeviceDb(aBridgeSettings.getUpnpDeviceDb()); theBridgeSettings.setConfigfile(aPath.toString());
theBridgeSettings.setVeraAddress(aBridgeSettings.getVeraAddress()); }
theBridgeSettings.setHarmonyAddress(aBridgeSettings.getHarmonyAddress());
theBridgeSettings.setHarmonyUser(aBridgeSettings.getHarmonyUser());
theBridgeSettings.setHarmonyPwd(aBridgeSettings.getHarmonyPwd());
theBridgeSettings.setUpnpStrict(aBridgeSettings.isUpnpStrict());
theBridgeSettings.setTraceupnp(aBridgeSettings.isTraceupnp());
theBridgeSettings.setNestuser(aBridgeSettings.getNestuser());
theBridgeSettings.setNestpwd(aBridgeSettings.getNestpwd());
theBridgeSettings.setVeraconfigured(aBridgeSettings.isValidVera());
theBridgeSettings.setHarmonyconfigured(aBridgeSettings.isValidHarmony());
theBridgeSettings.setNestConfigured(aBridgeSettings.isValidNest());
theBridgeSettings.setNumberoflogmessages(aBridgeSettings.getNumberoflogmessages());
theBridgeSettings.setFarenheit(aBridgeSettings.isFarenheit());
} }
public void save(BridgeSettingsDescriptor newBridgeSettings) { public void save(BridgeSettingsDescriptor newBridgeSettings) {
Logger log = LoggerFactory.getLogger(BridgeSettings.class);
log.debug("Save HA Bridge settings."); log.debug("Save HA Bridge settings.");
Path configPath = Paths.get(theBridgeSettings.getConfigfile()); Path configPath = Paths.get(theBridgeSettings.getConfigfile());
JsonTransformer aRenderer = new JsonTransformer(); JsonTransformer aRenderer = new JsonTransformer();
@@ -201,7 +199,6 @@ public class BridgeSettings extends BackupHandler {
private void configWriter(String content, Path filePath) { private void configWriter(String content, Path filePath) {
Logger log = LoggerFactory.getLogger(BridgeSettings.class);
if(Files.exists(filePath) && !Files.isWritable(filePath)){ if(Files.exists(filePath) && !Files.isWritable(filePath)){
log.error("Error file is not writable: " + filePath); log.error("Error file is not writable: " + filePath);
return; return;
@@ -230,8 +227,6 @@ public class BridgeSettings extends BackupHandler {
} }
private String configReader(Path filePath) { private String configReader(Path filePath) {
Logger log = LoggerFactory.getLogger(BridgeSettings.class);
String content = null; String content = null;
if(Files.notExists(filePath) || !Files.isReadable(filePath)){ if(Files.notExists(filePath) || !Files.isReadable(filePath)){
log.warn("Error reading the file: " + filePath + " - Does not exist or is not readable. continuing..."); log.warn("Error reading the file: " + filePath + " - Does not exist or is not readable. continuing...");

View File

@@ -1,6 +1,9 @@
package com.bwssystems.HABridge; package com.bwssystems.HABridge;
import java.util.List; import java.util.List;
import java.util.Map;
import com.bwssystems.HABridge.api.hue.WhitelistEntry;
public class BridgeSettingsDescriptor { public class BridgeSettingsDescriptor {
private String upnpconfigaddress; private String upnpconfigaddress;
@@ -22,6 +25,13 @@ 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;
private IpList haladdress;
private String haltoken;
private boolean halconfigured;
private Map<String, WhitelistEntry> whitelist;
private boolean settingsChanged;
public BridgeSettingsDescriptor() { public BridgeSettingsDescriptor() {
super(); super();
@@ -30,7 +40,11 @@ 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.halconfigured = false;
this.farenheit = true; this.farenheit = true;
this.whitelist = null;
this.settingsChanged = false;
} }
public String getUpnpConfigAddress() { public String getUpnpConfigAddress() {
return upnpconfigaddress; return upnpconfigaddress;
@@ -152,6 +166,48 @@ 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 IpList getHaladdress() {
return haladdress;
}
public void setHaladdress(IpList haladdress) {
this.haladdress = haladdress;
}
public String getHaltoken() {
return haltoken;
}
public void setHaltoken(String haltoken) {
this.haltoken = haltoken;
}
public boolean isHalconfigured() {
return halconfigured;
}
public void setHalconfigured(boolean halconfigured) {
this.halconfigured = halconfigured;
}
public Map<String, WhitelistEntry> getWhitelist() {
return whitelist;
}
public void setWhitelist(Map<String, WhitelistEntry> whitelist) {
this.whitelist = whitelist;
}
public boolean isSettingsChanged() {
return settingsChanged;
}
public void setSettingsChanged(boolean settingsChanged) {
this.settingsChanged = settingsChanged;
}
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 +235,22 @@ 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;
}
public Boolean isValidHal() {
if(this.getHaladdress() == null || this.getHaladdress().getDevices().size() <= 0)
return false;
List<NamedIP> devicesList = this.getHaladdress().getDevices();
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
return false;
if(this.getHaltoken() == null || this.getHaltoken().equals(""))
return false;
return true;
}
} }

View File

@@ -10,7 +10,9 @@ import com.bwssystems.HABridge.hue.HueMulator;
import com.bwssystems.HABridge.upnp.UpnpListener; 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.hal.HalHome;
import com.bwssystems.harmony.HarmonyHome; import com.bwssystems.harmony.HarmonyHome;
import com.bwssystems.hue.HueHome;
public class HABridge { public class HABridge {
@@ -34,6 +36,8 @@ public class HABridge {
DeviceResource theResources; DeviceResource theResources;
HarmonyHome harmonyHome; HarmonyHome harmonyHome;
NestHome nestHome; NestHome nestHome;
HueHome hueHome;
HalHome halHome;
HueMulator theHueMulator; HueMulator theHueMulator;
UpnpSettingsResource theSettingResponder; UpnpSettingsResource theSettingResponder;
UpnpListener theUpnpListener; UpnpListener theUpnpListener;
@@ -62,10 +66,14 @@ 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 hal configuration if available
halHome = new HalHome(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, halHome);
// 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,7 +85,10 @@ 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);
if(bridgeSettings.getBridgeSettingsDescriptor().isSettingsChanged())
bridgeSettings.save(bridgeSettings.getBridgeSettingsDescriptor());
bridgeSettings.getBridgeControl().setReinit(false); bridgeSettings.getBridgeControl().setReinit(false);
stop(); stop();
nestHome.closeTheNest(); nestHome.closeTheNest();

View 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;
}
}

View 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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -11,6 +11,7 @@ public class DeviceResponse {
private String name; private String name;
private String modelid; private String modelid;
private String manufacturername; private String manufacturername;
private String luminaireuniqueid;
private String uniqueid; private String uniqueid;
private String swversion; private String swversion;
@@ -70,15 +71,17 @@ public class DeviceResponse {
this.swversion = swversion; this.swversion = swversion;
} }
public String getLuminaireuniqueid() {
return luminaireuniqueid;
}
public void setLuminaireuniqueid(String luminaireuniqueid) {
this.luminaireuniqueid = luminaireuniqueid;
}
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());
@@ -86,6 +89,7 @@ public class DeviceResponse {
response.setType("Dimmable light"); response.setType("Dimmable light");
response.setModelid("LWB004"); response.setModelid("LWB004");
response.setSwversion("66012040"); response.setSwversion("66012040");
response.setLuminaireuniqueid(null);
return response; return response;
} }

View File

@@ -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{" +

View File

@@ -0,0 +1,18 @@
package com.bwssystems.HABridge.api.hue;
public class DeviceTypes {
private Boolean bridge;
private String[] lights;
public Boolean getBridge() {
return bridge;
}
public void setBridge(Boolean bridge) {
this.bridge = bridge;
}
public String[] getLights() {
return lights;
}
public void setLights(String[] lights) {
this.lights = lights;
}
}

View File

@@ -0,0 +1,33 @@
package com.bwssystems.HABridge.api.hue;
public class GroupResponse {
private DeviceState action;
private String[] lights;
private String name;
public DeviceState getAction() {
return action;
}
public void setAction(DeviceState action) {
this.action = action;
}
public String[] getLights() {
return lights;
}
public void setLights(String[] lights) {
this.lights = lights;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static GroupResponse createGroupResponse(String[] theLights) {
GroupResponse theResponse = new GroupResponse();
theResponse.setAction(DeviceState.createDeviceState());
theResponse.setName("Lightset 0");
theResponse.setLights(theLights);
return theResponse;
}
}

View File

@@ -4,22 +4,23 @@ 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, Map<String, WhitelistEntry> awhitelist) {
super(); super();
this.setConfig(HueConfig.createConfig(name, ipaddress, devicetype, userid)); this.setConfig(HueConfig.createConfig(name, ipaddress, awhitelist));
this.setRules(new HashMap<>()); this.setRules(new HashMap<>());
this.setSensors(new HashMap<>()); this.setSensors(new HashMap<>());
this.setSchedules(new HashMap<>()); this.setSchedules(new HashMap<>());
@@ -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;
} }

View File

@@ -6,7 +6,6 @@ import java.net.SocketException;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.TimeZone; import java.util.TimeZone;
@@ -29,18 +28,22 @@ public class HueConfig
private String localtime; private String localtime;
private String timezone; private String timezone;
private String zigbeechannel; private String zigbeechannel;
private String modelid;
private String bridgeid;
private Boolean factorynew;
private String replacesbridgeid;
private Map<String, WhitelistEntry> whitelist; private Map<String, WhitelistEntry> whitelist;
public static HueConfig createConfig(String name, String ipaddress, String devicetype, String userid) { public static HueConfig createConfig(String name, String ipaddress, Map<String, WhitelistEntry> awhitelist) {
HueConfig aConfig = new HueConfig(); HueConfig aConfig = new HueConfig();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
SimpleDateFormat dateFormatGmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); SimpleDateFormat dateFormatGmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
dateFormatGmt.setTimeZone(TimeZone.getTimeZone("UTC")); dateFormatGmt.setTimeZone(TimeZone.getTimeZone("UTC"));
aConfig.setMac(HueConfig.getMacAddress(ipaddress)); aConfig.setMac(HueConfig.getMacAddress(ipaddress));
aConfig.setApiversion("1.4.0"); aConfig.setApiversion("1.10.0");
aConfig.setPortalservices(false); aConfig.setPortalservices(false);
aConfig.setGateway(ipaddress); aConfig.setGateway(ipaddress);
aConfig.setSwversion("01005215"); aConfig.setSwversion("01028090");
aConfig.setLinkbutton(false); aConfig.setLinkbutton(false);
aConfig.setIpaddress(ipaddress); aConfig.setIpaddress(ipaddress);
aConfig.setProxyport(0); aConfig.setProxyport(0);
@@ -53,8 +56,10 @@ public class HueConfig
aConfig.setLocaltime(dateFormat.format(new Date())); aConfig.setLocaltime(dateFormat.format(new Date()));
aConfig.setTimezone(TimeZone.getDefault().getID()); aConfig.setTimezone(TimeZone.getDefault().getID());
aConfig.setZigbeechannel("6"); aConfig.setZigbeechannel("6");
Map<String, WhitelistEntry> awhitelist = new HashMap<>(); aConfig.setBridgeid(HuePublicConfig.getBridgeIdFromMac(aConfig.getMac(), ipaddress));
awhitelist.put(userid, WhitelistEntry.createEntry(devicetype)); aConfig.setModelid("BSB002");
aConfig.setFactorynew(false);
aConfig.setReplacesbridgeid(null);
aConfig.setWhitelist(awhitelist); aConfig.setWhitelist(awhitelist);
return aConfig; return aConfig;
@@ -235,4 +240,36 @@ public class HueConfig
public void setZigbeechannel(String zigbeechannel) { public void setZigbeechannel(String zigbeechannel) {
this.zigbeechannel = zigbeechannel; this.zigbeechannel = zigbeechannel;
} }
public String getModelid() {
return modelid;
}
public void setModelid(String modelid) {
this.modelid = modelid;
}
public String getBridgeid() {
return bridgeid;
}
public void setBridgeid(String bridgeid) {
this.bridgeid = bridgeid;
}
public Boolean getFactorynew() {
return factorynew;
}
public void setFactorynew(Boolean factorynew) {
this.factorynew = factorynew;
}
public String getReplacesbridgeid() {
return replacesbridgeid;
}
public void setReplacesbridgeid(String replacesbridgeid) {
this.replacesbridgeid = replacesbridgeid;
}
} }

View File

@@ -0,0 +1,19 @@
package com.bwssystems.HABridge.api.hue;
public class HueError {
private HueErrorDetails error;
public HueError(HueErrorDetails error) {
super();
this.error = error;
}
public HueErrorDetails getError() {
return error;
}
public void setError(HueErrorDetails error) {
this.error = error;
}
}

View File

@@ -0,0 +1,56 @@
package com.bwssystems.HABridge.api.hue;
public class HueErrorDetails {
private String type;
private String address;
private String description;
private String method_name;
private String resource_name;
private String value;
public HueErrorDetails(String type, String address, String description, String method_name, String resource_name,
String value) {
super();
this.type = type;
this.address = address;
this.description = description;
this.method_name = method_name;
this.resource_name = resource_name;
this.value = value;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getMethod_name() {
return method_name;
}
public void setMethod_name(String method_name) {
this.method_name = method_name;
}
public String getResource_name() {
return resource_name;
}
public void setResource_name(String resource_name) {
this.resource_name = resource_name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}

View File

@@ -0,0 +1,27 @@
package com.bwssystems.HABridge.api.hue;
import java.util.ArrayList;
public class HueErrorResponse {
private ArrayList<HueError> theErrors;
public HueErrorResponse() {
super();
theErrors = new ArrayList<HueError>();
}
public void addError(HueError anError) {
theErrors.add(anError);
}
public HueError[] getTheErrors() {
HueError theList[] = new HueError[theErrors.size()];
theList = theErrors.toArray(theList);
return theList;
}
public void setTheErrors(ArrayList<HueError> theErrors) {
this.theErrors = theErrors;
}
}

View File

@@ -0,0 +1,154 @@
package com.bwssystems.HABridge.api.hue;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.StringTokenizer;
import javax.xml.bind.DatatypeConverter;
public class HuePublicConfig
{
private String name;
private String apiversion;
private String swversion;
private String mac;
private String bridgeid;
private String replacesbridgeid;
private Boolean factorynew;
private String modelid;
public static HuePublicConfig createConfig(String name, String ipaddress) {
HuePublicConfig aConfig = new HuePublicConfig();
aConfig.setMac(HuePublicConfig.getMacAddress(ipaddress));
aConfig.setApiversion("1.10.0");
aConfig.setSwversion("01028090");
aConfig.setName(name);
aConfig.setBridgeid(HuePublicConfig.getBridgeIdFromMac(aConfig.getMac(), ipaddress));
aConfig.setModelid("BSB002");
aConfig.setFactorynew(false);
aConfig.setReplacesbridgeid(null);
return aConfig;
}
private static String getMacAddress(String addr)
{
InetAddress ip;
StringBuilder sb = new StringBuilder();
try {
ip = InetAddress.getByName(addr);
NetworkInterface network = NetworkInterface.getByInetAddress(ip);
byte[] mac = network.getHardwareAddress();
for (int i = 0; i < mac.length; i++) {
sb.append(String.format("%02X%s", mac[i], (i < mac.length - 1) ? ":" : ""));
}
} catch (UnknownHostException e) {
sb.append("00:00:88:00:bb:ee");
} catch (SocketException e){
sb.append("00:00:88:00:bb:ee");
} catch (Exception e){
sb.append("00:00:88:00:bb:ee");
}
return sb.toString();
}
protected static String getBridgeIdFromMac(String macAddr, String ipAddr)
{
StringTokenizer st = new StringTokenizer(macAddr, ":");
String bridgeId = "";
String port = null;
while(st.hasMoreTokens()) {
bridgeId = bridgeId + st.nextToken();
}
if(ipAddr.contains(":")) {
port = ipAddr.substring(ipAddr.indexOf(":"));
BigInteger bigInt = BigInteger.valueOf(Integer.getInteger(port).intValue());
byte[] theBytes = bigInt.toByteArray();
bridgeId = bridgeId + DatatypeConverter.printHexBinary(theBytes);
}
else
bridgeId = bridgeId + "0800";
return bridgeId;
}
public String getMac() {
return mac;
}
public void setMac(String mac) {
this.mac = mac;
}
public String getSwversion() {
return swversion;
}
public void setSwversion(String swversion) {
this.swversion = swversion;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getApiversion() {
return apiversion;
}
public void setApiversion(String apiversion) {
this.apiversion = apiversion;
}
public String getModelid() {
return modelid;
}
public void setModelid(String modelid) {
this.modelid = modelid;
}
public String getBridgeid() {
return bridgeid;
}
public void setBridgeid(String bridgeid) {
this.bridgeid = bridgeid;
}
public Boolean getFactorynew() {
return factorynew;
}
public void setFactorynew(Boolean factorynew) {
this.factorynew = factorynew;
}
public String getReplacesbridgeid() {
return replacesbridgeid;
}
public void setReplacesbridgeid(String replacesbridgeid) {
this.replacesbridgeid = replacesbridgeid;
}
}

View File

@@ -0,0 +1,136 @@
package com.bwssystems.HABridge.api.hue;
// import java.util.ArrayList;
import java.util.List;
/**
* Created by arm on 4/14/15.
*/
public class StateChangeBody {
private boolean on;
private int bri;
private int hue;
private int sat;
private String effect;
private int ct;
private String alert;
private List<Double> xy;
private int transitiontime;
private int bri_inc;
private int hue_inc;
private int sat_inc;
private List<Double> xy_inc;
private int ct_inc;
public boolean isOn() {
return on;
}
public void setOn(boolean on) {
this.on = on;
}
public int getBri() {
return bri;
}
public void setBri(int 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() {
return effect;
}
public void setEffect(String effect) {
this.effect = effect;
}
public int getCt() {
return ct;
}
public void setCt(int ct) {
this.ct = ct;
}
public String getAlert() {
return alert;
}
public void setAlert(String alert) {
this.alert = alert;
}
public List<Double> getXy() {
return xy;
}
public void setXy(List<Double> xy) {
this.xy = xy;
}
public int getTransitiontime() {
return transitiontime;
}
public void setTransitiontime(int transitiontime) {
this.transitiontime = transitiontime;
}
public int getBri_inc() {
return bri_inc;
}
public void setBri_inc(int bri_inc) {
this.bri_inc = bri_inc;
}
public int getHue_inc() {
return hue_inc;
}
public void setHue_inc(int hue_inc) {
this.hue_inc = hue_inc;
}
public int getSat_inc() {
return sat_inc;
}
public void setSat_inc(int sat_inc) {
this.sat_inc = sat_inc;
}
public List<Double> getXy_inc() {
return xy_inc;
}
public void setXy_inc(List<Double> xy_inc) {
this.xy_inc = xy_inc;
}
public int getCt_inc() {
return ct_inc;
}
public void setCt_inc(int ct_inc) {
this.ct_inc = ct_inc;
}
}

View File

@@ -3,20 +3,36 @@ package com.bwssystems.HABridge.api.hue;
public class Swupdate public class Swupdate
{ {
private Integer updatestate;
private Boolean checkforupdate;
private DeviceTypes devicetypes;
private String text; private String text;
private Boolean notify; private Boolean notify;
private Integer updatestate;
private String url; private String url;
public static Swupdate createSwupdate() { public static Swupdate createSwupdate() {
Swupdate aSwupdate = new Swupdate(); Swupdate aSwupdate = new Swupdate();
aSwupdate.setUpdatestate(0);
aSwupdate.setCheckforupdate(false);
aSwupdate.setDevicetypes(new DeviceTypes());
aSwupdate.setNotify(false); aSwupdate.setNotify(false);
aSwupdate.setText(""); aSwupdate.setText("");
aSwupdate.setUpdatestate(0);
aSwupdate.setUrl(""); aSwupdate.setUrl("");
return aSwupdate; return aSwupdate;
} }
public Boolean getCheckforupdate() {
return checkforupdate;
}
public void setCheckforupdate(Boolean checkforupdate) {
this.checkforupdate = checkforupdate;
}
public DeviceTypes getDevicetypes() {
return devicetypes;
}
public void setDevicetypes(DeviceTypes devicetypes) {
this.devicetypes = devicetypes;
}
public String getText() { public String getText() {
return text; return text;
} }

View File

@@ -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;
}
} }

View File

@@ -21,7 +21,9 @@ import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.dao.DeviceRepository; 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.hal.HalHome;
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 +40,11 @@ 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 HalHome halHome;
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, HalHome aHalHome) {
this.deviceRepository = new DeviceRepository(theSettings.getUpnpDeviceDb()); this.deviceRepository = new DeviceRepository(theSettings.getUpnpDeviceDb());
if(theSettings.isValidVera()) if(theSettings.isValidVera())
@@ -57,6 +61,17 @@ 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;
if(theSettings.isValidHal())
this.halHome = aHalHome;
else
this.halHome = null;
setupEndpoints(); setupEndpoints();
} }
@@ -245,6 +260,26 @@ 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 + "/hal/devices", "application/json", (request, response) -> {
log.debug("Get hal items");
if(halHome == null) {
response.status(HttpStatus.SC_NOT_FOUND);
return new ErrorMessage("A Hal is not available.");
}
response.status(HttpStatus.SC_OK);
return halHome.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);

File diff suppressed because it is too large Load Diff

View File

@@ -22,6 +22,21 @@ public class UpnpListener {
private boolean strict; private boolean strict;
private boolean traceupnp; private boolean traceupnp;
private BridgeControlDescriptor bridgeControl; private BridgeControlDescriptor bridgeControl;
private boolean discoveryTemplateLatest;
private String discoveryTemplate = "HTTP/1.1 200 OK\r\n" +
"CACHE-CONTROL: max-age=86400\r\n" +
"EXT:\r\n" +
"LOCATION: http://%s:%s/description.xml\r\n" +
"SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/1.10.0\r\n" +
"ST: urn:schemas-upnp-org:device:basic:1\r\n" +
"USN: uuid:Socket-1_0-221438K0100073::urn:schemas-upnp-org:device:basic:1\r\n\r\n";
private String discoveryTemplateOld = "HTTP/1.1 200 OK\r\n" +
"CACHE-CONTROL: max-age=86400\r\n" +
"EXT:\r\n" +
"LOCATION: http://%s:%s/description.xml\r\n" +
"SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/0.1\r\n" +
"ST: urn:schemas-upnp-org:device:basic:1\r\n" +
"USN: uuid:Socket-1_0-221438K0100073::urn:schemas-upnp-org:device:basic:1\r\n\r\n";
public UpnpListener(BridgeSettingsDescriptor theSettings, BridgeControlDescriptor theControl) { public UpnpListener(BridgeSettingsDescriptor theSettings, BridgeControlDescriptor theControl) {
super(); super();
@@ -31,15 +46,53 @@ public class UpnpListener {
strict = theSettings.isUpnpStrict(); strict = theSettings.isUpnpStrict();
traceupnp = theSettings.isTraceupnp(); traceupnp = theSettings.isTraceupnp();
bridgeControl = theControl; bridgeControl = theControl;
discoveryTemplateLatest = true;
} }
@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;
boolean portLoopControl = true;
int retryCount = 0;
while(portLoopControl) {
try {
responseSocket = new DatagramSocket(upnpResponsePort);
if(retryCount > 0)
log.info("Upnp Response Port issue, found open port: " + upnpResponsePort);
portLoopControl = false;
} catch(SocketException e) {
if(retryCount == 0)
log.warn("Upnp Response Port is in use, starting loop to find open port for 20 tries - configured port is: " + upnpResponsePort);
if(retryCount >= 20) {
portLoopControl = false;
log.error("Upnp Response Port issue, could not find open port - last port tried: " + upnpResponsePort + " with message: " + e.getMessage());
return false;
}
}
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;
}
try (DatagramSocket responseSocket = new DatagramSocket(upnpResponsePort);
MulticastSocket upnpMulticastSocket = new MulticastSocket(Configuration.UPNP_DISCOVERY_PORT);) {
InetSocketAddress socketAddress = new InetSocketAddress(Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT); InetSocketAddress socketAddress = new InetSocketAddress(Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT);
Enumeration<NetworkInterface> ifs = NetworkInterface.getNetworkInterfaces(); try {
ifs = NetworkInterface.getNetworkInterfaces();
} catch (SocketException e) {
log.error("Could not get network interfaces for this machine: " + e.getMessage());
return false;
}
while (ifs.hasMoreElements()) { while (ifs.hasMoreElements()) {
NetworkInterface xface = ifs.nextElement(); NetworkInterface xface = ifs.nextElement();
@@ -59,24 +112,40 @@ public class UpnpListener {
} }
log.debug("Checking " + name + " to our interface set"); log.debug("Checking " + name + " to our interface set");
if (IPsPerNic > 0) { 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...."); log.info("UPNP Discovery Listener running and ready....");
boolean loopControl = true; boolean loopControl = true;
boolean error = false;
while (loopControl) { // trigger shutdown here while (loopControl) { // trigger shutdown here
byte[] buf = new byte[1024]; byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length); DatagramPacket packet = new DatagramPacket(buf, buf.length);
try {
upnpMulticastSocket.receive(packet); upnpMulticastSocket.receive(packet);
if (isSSDPDiscovery(packet)) { if (isSSDPDiscovery(packet)) {
try {
sendUpnpResponse(responseSocket, packet.getAddress(), packet.getPort()); sendUpnpResponse(responseSocket, packet.getAddress(), packet.getPort());
} catch (IOException e) {
log.error("UpnpListener encountered an error sending upnp response packet. Shutting down", e);
error = true;
} }
if(bridgeControl.isReinit() || bridgeControl.isStop()) { }
} catch (IOException e) {
log.error("UpnpListener encountered an error reading socket. Shutting down", e);
error = true;
}
if (error || bridgeControl.isReinit() || bridgeControl.isStop()) {
try { try {
Thread.sleep(1000); Thread.sleep(1000);
} catch (InterruptedException e) { } catch (InterruptedException e) {
@@ -87,15 +156,14 @@ public class UpnpListener {
} }
upnpMulticastSocket.close(); upnpMulticastSocket.close();
responseSocket.close(); responseSocket.close();
} catch (IOException e) {
log.error("UpnpListener encountered an error opening sockets. Shutting down", e);
}
if (bridgeControl.isReinit()) 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();
} }
@@ -137,16 +205,12 @@ public class UpnpListener {
return false; return false;
} }
String discoveryTemplate = "HTTP/1.1 200 OK\r\n" +
"CACHE-CONTROL: max-age=86400\r\n" +
"EXT:\r\n" +
"LOCATION: http://%s:%s/description.xml\r\n" +
"SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/0.1\r\n" +
"ST: urn:schemas-upnp-org:device:basic:1\r\n" +
"USN: uuid:Socket-1_0-221438K0100073::urn:schemas-upnp-org:device:basic:1\r\n\r\n";
protected void sendUpnpResponse(DatagramSocket socket, InetAddress requester, int sourcePort) throws IOException { protected void sendUpnpResponse(DatagramSocket socket, InetAddress requester, int sourcePort) throws IOException {
String discoveryResponse = null; String discoveryResponse = null;
if(discoveryTemplateLatest)
discoveryResponse = String.format(discoveryTemplate, responseAddress, httpServerPort); discoveryResponse = String.format(discoveryTemplate, responseAddress, httpServerPort);
else
discoveryResponse = String.format(discoveryTemplateOld, Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT, responseAddress, httpServerPort);
if(traceupnp) if(traceupnp)
log.info("Traceupnp: sendUpnpResponse discovery template with address: " + responseAddress + " and port: " + httpServerPort); log.info("Traceupnp: sendUpnpResponse discovery template with address: " + responseAddress + " and port: " + httpServerPort);
else else

View File

@@ -15,26 +15,51 @@ public class UpnpSettingsResource {
private BridgeSettingsDescriptor theSettings; private BridgeSettingsDescriptor theSettings;
private String hueTemplate = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" + "<root xmlns=\"urn:schemas-upnp-org:device-1-0\">\n" private String hueTemplate = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
+ "<specVersion>\n" + "<major>1</major>\n" + "<minor>0</minor>\n" + "</specVersion>\n" + "<root xmlns=\"urn:schemas-upnp-org:device-1-0\">\n"
+ "<URLBase>http://%s:%s/</URLBase>\n" + // hostname string + "<specVersion>\n"
"<device>\n" + "<deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>\n" + "<major>1</major>\n"
+ "<friendlyName>HA-Bridge (%s)</friendlyName>\n" + "<minor>0</minor>\n"
+ "</specVersion>\n"
+ "<URLBase>http://%s:%s/</URLBase>\n"
+ "<device>\n"
+ "<deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>\n"
+ "<friendlyName>Philips hue (%s)</friendlyName>\n"
+ "<manufacturer>Royal Philips Electronics</manufacturer>\n" + "<manufacturer>Royal Philips Electronics</manufacturer>\n"
+ "<manufacturerURL>http://www.bwssystems.com</manufacturerURL>\n" + "<manufacturerURL>http://www.philips.com</manufacturerURL>\n"
+ "<modelDescription>Hue Emulator for HA bridge</modelDescription>\n" + "<modelDescription>Philips hue Personal Wireless Lighting</modelDescription>\n"
+ "<modelName>Philips hue bridge 2012</modelName>\n" + "<modelNumber>929000226503</modelNumber>\n" + "<modelName>Philips hue bridge 2015</modelName>\n"
+ "<modelURL>http://www.bwssystems.com/apps.html</modelURL>\n" + "<modelNumber>BSB002</modelNumber>\n"
+ "<modelURL>http://www.meethue.com</modelURL>\n"
+ "<serialNumber>0017880ae670</serialNumber>\n" + "<serialNumber>0017880ae670</serialNumber>\n"
+ "<UDN>uuid:88f6698f-2c83-4393-bd03-cd54a9f8595</UDN>\n" + "<serviceList>\n" + "<service>\n" + "<UDN>uuid:2f402f80-da50-11e1-9b23-001788102201</UDN>\n"
+ "<serviceType>(null)</serviceType>\n" + "<serviceId>(null)</serviceId>\n" + "<serviceList>\n"
+ "<controlURL>(null)</controlURL>\n" + "<eventSubURL>(null)</eventSubURL>\n" + "<service>\n"
+ "<SCPDURL>(null)</SCPDURL>\n" + "</service>\n" + "</serviceList>\n" + "<serviceType>(null)</serviceType>\n"
+ "<presentationURL>index.html</presentationURL>\n" + "<iconList>\n" + "<icon>\n" + "<serviceId>(null)</serviceId>\n"
+ "<mimetype>image/png</mimetype>\n" + "<height>48</height>\n" + "<width>48</width>\n" + "<controlURL>(null)</controlURL>\n"
+ "<depth>24</depth>\n" + "<url>hue_logo_0.png</url>\n" + "</icon>\n" + "<icon>\n" + "<eventSubURL>(null)</eventSubURL>\n"
+ "<mimetype>image/png</mimetype>\n" + "<height>120</height>\n" + "<width>120</width>\n" + "<SCPDURL>(null)</SCPDURL>\n"
+ "<depth>24</depth>\n" + "<url>hue_logo_3.png</url>\n" + "</icon>\n" + "</iconList>\n" + "</device>\n" + "</service>\n"
+ "</serviceList>\n"
+ "<presentationURL>index.html</presentationURL>\n"
+ "<iconList>\n"
+ "<icon>\n"
+ "<mimetype>image/png</mimetype>\n"
+ "<height>48</height>\n"
+ "<width>48</width>\n"
+ "<depth>24</depth>\n"
+ "<url>hue_logo_0.png</url>\n"
+ "</icon>\n"
+ "<icon>\n"
+ "<mimetype>image/png</mimetype>\n"
+ "<height>120</height>\n"
+ "<width>120</width>\n"
+ "<depth>24</depth>\n"
+ "<url>hue_logo_3.png</url>\n"
+ "</icon>\n"
+ "</iconList>\n"
+ "</device>\n"
+ "</root>\n"; + "</root>\n";
public UpnpSettingsResource(BridgeSettingsDescriptor theBridgeSettings) { public UpnpSettingsResource(BridgeSettingsDescriptor theBridgeSettings) {
@@ -47,9 +72,9 @@ public class UpnpSettingsResource {
// http://ip_adress:port/description.xml which returns the xml configuration for the hue emulator // http://ip_adress:port/description.xml which returns the xml configuration for the hue emulator
get("/description.xml", "application/xml; charset=utf-8", (request, response) -> { get("/description.xml", "application/xml; charset=utf-8", (request, response) -> {
if(theSettings.isTraceupnp()) if(theSettings.isTraceupnp())
log.info("Traceupnp: upnp device settings requested: " + request.params(":id") + " from " + request.ip() + ":" + request.port()); log.info("Traceupnp: upnp device settings requested: " + " from " + request.ip() + ":" + request.port());
else else
log.debug("upnp device settings requested: " + request.params(":id") + " from " + request.ip() + ":" + request.port()); log.debug("upnp device settings requested: " + " from " + request.ip() + ":" + request.port());
String portNumber = Integer.toString(request.port()); String portNumber = Integer.toString(request.port());
String filledTemplate = null; String filledTemplate = null;
filledTemplate = String.format(hueTemplate, theSettings.getUpnpConfigAddress(), portNumber, theSettings.getUpnpConfigAddress()); filledTemplate = String.format(hueTemplate, theSettings.getUpnpConfigAddress(), portNumber, theSettings.getUpnpConfigAddress());
@@ -72,5 +97,17 @@ public class UpnpSettingsResource {
return filledTemplate; return filledTemplate;
} ); } );
// http://ip_adress:port/favicon.ico
get("/favicon.ico", "application/xml; charset=utf-8", (request, response) -> {
return "";
} );
// http://ip_adress:port/hue_logo_0.png
get("/hue_logo_0.png", "application/xml; charset=utf-8", (request, response) -> {
return "";
} );
// http://ip_adress:port/hue_logo_3.png
get("/hue_logo_3.png", "application/xml; charset=utf-8", (request, response) -> {
return "";
} );
} }
} }

View File

@@ -0,0 +1,17 @@
package com.bwssystems.hal;
import java.util.List;
import com.google.gson.annotations.SerializedName;
public class DeviceElements {
@SerializedName(value="DeviceElements", alternate={"SceneElements", "GroupElements", "HVACElements", "MacroElements", "IrElements", "IrButtons"})
private List<DeviceName> DeviceElements;
public List<DeviceName> getDeviceElements() {
return DeviceElements;
}
public void setDeviceElements(List<DeviceName> deviceElements) {
DeviceElements = deviceElements;
}
}

View File

@@ -0,0 +1,17 @@
package com.bwssystems.hal;
import com.google.gson.annotations.SerializedName;
public class DeviceName {
@SerializedName(value="DeviceName", alternate={"SceneName", "GroupName", "HVACName", "MacroName", "IrName", "IrButton"})
private String DeviceName;
public String getDeviceName() {
return DeviceName;
}
public void setDeviceName(String deviceName) {
DeviceName = deviceName;
}
}

View File

@@ -0,0 +1,39 @@
package com.bwssystems.hal;
public class HalDevice {
private String haldevicetype;
private String haldevicename;
private String haladdress;
private String halname;
private DeviceElements buttons;
public String getHaldevicetype() {
return haldevicetype;
}
public void setHaldevicetype(String haldevicetype) {
this.haldevicetype = haldevicetype;
}
public String getHaldevicename() {
return haldevicename;
}
public void setHaldevicename(String haldevicename) {
this.haldevicename = haldevicename;
}
public String getHaladdress() {
return haladdress;
}
public void setHaladdress(String haladdress) {
this.haladdress = haladdress;
}
public String getHalname() {
return halname;
}
public void setHalname(String halname) {
this.halname = halname;
}
public DeviceElements getButtons() {
return buttons;
}
public void setButtons(DeviceElements buttons) {
this.buttons = buttons;
}
}

View File

@@ -0,0 +1,113 @@
package com.bwssystems.hal;
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;
public class HalHome {
private static final Logger log = LoggerFactory.getLogger(HalHome.class);
private Map<String, HalInfo> hals;
public HalHome(BridgeSettingsDescriptor bridgeSettings) {
super();
hals = new HashMap<String, HalInfo>();
if(!bridgeSettings.isValidHal())
return;
Iterator<NamedIP> theList = bridgeSettings.getHaladdress().getDevices().iterator();
while(theList.hasNext()) {
NamedIP aHal = theList.next();
try {
hals.put(aHal.getName(), new HalInfo(aHal, bridgeSettings.getHaltoken()));
} catch (Exception e) {
log.error("Cannot get harmony client (" + aHal.getName() + ") setup, Exiting with message: " + e.getMessage(), e);
return;
}
}
}
public List<HalDevice> getDevices() {
log.debug("consolidating devices for hues");
List<HalDevice> theResponse = null;
Iterator<String> keys = hals.keySet().iterator();
List<HalDevice> deviceList = new ArrayList<HalDevice>();
while(keys.hasNext()) {
String key = keys.next();
theResponse = hals.get(key).getLights();
if(theResponse != null)
addHalDevices(deviceList, theResponse, key);
else {
log.warn("Cannot get lights for Hal with name: " + key + ", skipping this HAL.");
continue;
}
theResponse = hals.get(key).getAppliances();
if(theResponse != null)
addHalDevices(deviceList, theResponse, key);
else
log.warn("Cannot get appliances for Hal with name: " + key);
theResponse = hals.get(key).getTheatre();
if(theResponse != null)
addHalDevices(deviceList, theResponse, key);
else
log.warn("Cannot get theatre for Hal with name: " + key);
theResponse = hals.get(key).getCustom();
if(theResponse != null)
addHalDevices(deviceList, theResponse, key);
else
log.warn("Cannot get custom for Hal with name: " + key);
theResponse = hals.get(key).getHVAC();
if(theResponse != null)
addHalDevices(deviceList, theResponse, key);
else
log.warn("Cannot get HVAC for Hal with name: " + key);
theResponse = hals.get(key).getHome(key);
if(theResponse != null)
addHalDevices(deviceList, theResponse, key);
else
log.warn("Cannot get Homes for Hal with name: " + key);
theResponse = hals.get(key).getGroups();
if(theResponse != null)
addHalDevices(deviceList, theResponse, key);
else
log.warn("Cannot get Groups for Hal with name: " + key);
theResponse = hals.get(key).getMacros();
if(theResponse != null)
addHalDevices(deviceList, theResponse, key);
else
log.warn("Cannot get Macros for Hal with name: " + key);
theResponse = hals.get(key).getScenes();
if(theResponse != null)
addHalDevices(deviceList, theResponse, key);
else
log.warn("Cannot get Scenes for Hal with name: " + key);
theResponse = hals.get(key).getButtons();
if(theResponse != null)
addHalDevices(deviceList, theResponse, key);
else
log.warn("Cannot get Buttons for Hal with name: " + key);
}
return deviceList;
}
private Boolean addHalDevices(List<HalDevice> theDeviceList, List<HalDevice> theSourceList, String theKey) {
Iterator<HalDevice> devices = theSourceList.iterator();
while(devices.hasNext()) {
HalDevice theDevice = devices.next();
HalDevice aNewHalDevice = new HalDevice();
aNewHalDevice.setHaldevicetype(theDevice.getHaldevicetype());
aNewHalDevice.setHaldevicename(theDevice.getHaldevicename());
aNewHalDevice.setButtons(theDevice.getButtons());
aNewHalDevice.setHaladdress(hals.get(theKey).getHalAddress().getIp());
aNewHalDevice.setHalname(theKey);
theDeviceList.add(aNewHalDevice);
}
return true;
}
}

View File

@@ -0,0 +1,206 @@
package com.bwssystems.hal;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
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.util.TextStringFormatter;
import com.google.gson.Gson;
public class HalInfo {
private static final Logger log = LoggerFactory.getLogger(HalInfo.class);
private static final String DEVICE_REQUEST = "/DeviceData!DeviceCmd=GetNames!DeviceType=";
private static final String HVAC_REQUEST = "/HVACData!HVACCmd=GetNames";
private static final String GROUP_REQUEST = "/GroupData!GroupCmd=GetNames";
private static final String MACRO_REQUEST = "/MacroData!MacroCmd=GetNames";
private static final String SCENE_REQUEST = "/SceneData!SceneCmd=GetNames";
private static final String IRDATA_REQUEST = "/IrData!IRCmd=GetNames";
private static final String IRBUTTON_REQUEST = "/IrData!IRCmd=GetButtons!IrDevice=";
private static final String TOKEN_REQUEST = "?Token=";
private static final String LIGHT_REQUEST = "Light";
private static final String APPL_REQUEST = "Appl";
// private static final String VIDEO_REQUEST = "Video";
private static final String THEATRE_REQUEST = "Theatre";
private static final String CUSTOM_REQUEST = "Custom";
private static final String HVAC_TYPE = "HVAC";
private static final String HOME_TYPE = "Home";
private static final String GROUP_TYPE = "Group";
private static final String MACRO_TYPE = "Macro";
private static final String SCENE_TYPE = "Scene";
private static final String IRDATA_TYPE = "IrData";
private HttpClient httpClient;
private NamedIP halAddress;
private String theToken;
public HalInfo(NamedIP addressName, String aGivenToken) {
super();
httpClient = HttpClients.createDefault();
halAddress = addressName;
theToken = aGivenToken;
}
public List<HalDevice> getLights() {
return getHalDevices(DEVICE_REQUEST + LIGHT_REQUEST + TOKEN_REQUEST, LIGHT_REQUEST);
}
public List<HalDevice> getAppliances() {
return getHalDevices(DEVICE_REQUEST + APPL_REQUEST + TOKEN_REQUEST, APPL_REQUEST);
}
public List<HalDevice> getTheatre() {
return getHalDevices(DEVICE_REQUEST + THEATRE_REQUEST + TOKEN_REQUEST, THEATRE_REQUEST);
}
public List<HalDevice> getCustom() {
return getHalDevices(DEVICE_REQUEST + CUSTOM_REQUEST + TOKEN_REQUEST, CUSTOM_REQUEST);
}
public List<HalDevice> getHVAC() {
return getHalDevices(HVAC_REQUEST + TOKEN_REQUEST, HVAC_TYPE);
}
public List<HalDevice> getGroups() {
return getHalDevices(GROUP_REQUEST + TOKEN_REQUEST, GROUP_TYPE);
}
public List<HalDevice> getMacros() {
return getHalDevices(MACRO_REQUEST + TOKEN_REQUEST, MACRO_TYPE);
}
public List<HalDevice> getScenes() {
return getHalDevices(SCENE_REQUEST + TOKEN_REQUEST, SCENE_TYPE);
}
public List<HalDevice> getButtons() {
List<HalDevice> irDataDevices = getHalDevices(IRDATA_REQUEST + TOKEN_REQUEST, IRDATA_TYPE);
return getDeviceButtons(irDataDevices);
}
public List<HalDevice> getHome(String theDeviceName) {
List<HalDevice> deviceList = null;
deviceList = new ArrayList<HalDevice>();
HalDevice aNewHalDevice = new HalDevice();
aNewHalDevice.setHaldevicetype(HOME_TYPE);
aNewHalDevice.setHaldevicename(theDeviceName);
deviceList.add(aNewHalDevice);
return deviceList;
}
private List<HalDevice> getHalDevices(String apiType, String deviceType) {
DeviceElements theHalApiResponse = null;
List<HalDevice> deviceList = null;
String theUrl = null;
String theData;
theUrl = "http://" + halAddress.getIp() + apiType + theToken;
theData = doHttpGETRequest(theUrl);
if(theData != null) {
log.debug("GET " + deviceType + " HalApiResponse - data: " + theData);
theHalApiResponse = new Gson().fromJson(theData, DeviceElements.class);
if(theHalApiResponse.getDeviceElements() == null) {
StatusDescription theStatus = new Gson().fromJson(theData, StatusDescription.class);
if(theStatus.getStatus() == null) {
log.warn("Cannot get an devices for type " + deviceType + " for hal " + halAddress.getName() + " as response is not parsable.");
}
else {
log.warn("Cannot get an devices for type " + deviceType + " for hal " + halAddress.getName() + ". Status: " + theStatus.getStatus() + ", with description: " + theStatus.getDescription());
}
return deviceList;
}
deviceList = new ArrayList<HalDevice>();
Iterator<DeviceName> theDeviceNames = theHalApiResponse.getDeviceElements().iterator();
while(theDeviceNames.hasNext()) {
DeviceName theDevice = theDeviceNames.next();
HalDevice aNewHalDevice = new HalDevice();
aNewHalDevice.setHaldevicetype(deviceType);
aNewHalDevice.setHaldevicename(theDevice.getDeviceName());
deviceList.add(aNewHalDevice);
}
}
else {
log.warn("Get Hal device types " + deviceType + " for " + halAddress.getName() + " - returned null, no data.");
}
return deviceList;
}
private List<HalDevice> getDeviceButtons(List<HalDevice> theIrDevices) {
DeviceElements theHalApiResponse = null;
List<HalDevice> deviceList = null;
String theUrl = null;
String theData;
if(theIrDevices == null)
return null;
Iterator<HalDevice> theHalDevices = theIrDevices.iterator();
deviceList = new ArrayList<HalDevice>();
while (theHalDevices.hasNext()) {
HalDevice theHalDevice = theHalDevices.next();
theUrl = "http://" + halAddress.getIp() + IRBUTTON_REQUEST + TextStringFormatter.forQuerySpaceUrl(theHalDevice.getHaldevicename()) + TOKEN_REQUEST + theToken;
theData = doHttpGETRequest(theUrl);
if (theData != null) {
log.debug("GET IrData for IR Device " + theHalDevice.getHaldevicename() + " HalApiResponse - data: " + theData);
theHalApiResponse = new Gson().fromJson(theData, DeviceElements.class);
if (theHalApiResponse.getDeviceElements() == null) {
StatusDescription theStatus = new Gson().fromJson(theData, StatusDescription.class);
if (theStatus.getStatus() == null) {
log.warn("Cannot get buttons for IR Device " + theHalDevice.getHaldevicename() + " for hal "
+ halAddress.getName() + " as response is not parsable.");
} else {
log.warn("Cannot get buttons for IR Device " + theHalDevice.getHaldevicename() + " for hal "
+ halAddress.getName() + ". Status: " + theStatus.getStatus() + ", with description: "
+ theStatus.getDescription());
}
return deviceList;
}
theHalDevice.setButtons(theHalApiResponse);
deviceList.add(theHalDevice);
} else {
log.warn("Get Hal buttons for IR Device " + theHalDevice.getHaldevicename() + " for "
+ halAddress.getName() + " - returned null, no data.");
}
}
return deviceList;
}
// This function executes the url against the hal
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 getHalAddress() {
return halAddress;
}
public void setHalAddress(NamedIP halAddress) {
this.halAddress = halAddress;
}
}

View File

@@ -0,0 +1,18 @@
package com.bwssystems.hal;
public class StatusDescription {
private String Status;
private String Description;
public String getStatus() {
return Status;
}
public void setStatus(String status) {
Status = status;
}
public String getDescription() {
return Description;
}
public void setDescription(String description) {
Description = description;
}
}

View 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;
}
}

View 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;
}
}

View File

@@ -0,0 +1,5 @@
package com.bwssystems.hue;
public interface HueErrorStringSet {
public void setErrorString(String anError);
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View File

@@ -221,6 +221,9 @@ public final class TextStringFormatter {
public static String forQuerySpace(String aURL) { public static String forQuerySpace(String aURL) {
return aURL.replace(" ", "\u0020"); return aURL.replace(" ", "\u0020");
} }
public static String forQuerySpaceUrl(String aURL) {
return aURL.replace(" ", "%20");
}
/** /**
* Synonym for <tt>URLEncoder.encode(String, "UTF-8")</tt>. * Synonym for <tt>URLEncoder.encode(String, "UTF-8")</tt>.
* *

View File

@@ -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));
} }
} }

View File

@@ -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;

View File

@@ -1,5 +1,5 @@
.scrollableContainer { .scrollableContainer {
height: 800px; max-height: 436px; /* sets max-height value for all standards-compliant browsers */
position: relative; position: relative;
padding-top: 35px; padding-top: 35px;
overflow: hidden; overflow: hidden;
@@ -28,7 +28,8 @@
} }
.scrollArea { .scrollArea {
height: 100%; _height: expression( this.scrollHeight > 599 ? "600px" : "auto" ); /* sets max-height for IE6 */
max-height: 400px; /* sets max-height value for all standards-compliant browsers */
overflow-x: auto; overflow-x: auto;
overflow-y: auto; overflow-y: auto;
border: 1px solid #d5d5d5; border: 1px solid #d5d5d5;

View File

@@ -31,6 +31,12 @@ 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'
}).when('/haldevices', {
templateUrl: 'views/haldevice.html',
controller: 'HalController'
}).otherwise({ }).otherwise({
templateUrl: 'views/configuration.html', templateUrl: 'views/configuration.html',
controller: 'ViewingController' controller: 'ViewingController'
@@ -42,14 +48,30 @@ app.run( function (bridgeService) {
bridgeService.getHABridgeVersion(); bridgeService.getHABridgeVersion();
}); });
String.prototype.replaceAll = function(search, replace)
{
//if replace is not sent, return original string otherwise it will
//replace search string with 'undefined'.
if (replace === undefined) {
return this.toString();
}
return this.replace(new RegExp('[' + search + ']', 'g'), replace);
};
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, showHal: 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') {
if(error.data != null)
toastContent = toastContent + " " + error.data.message + " with status: " + error.statusText + " - " + error.status; 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 +116,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 +127,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 +165,16 @@ app.service('bridgeService', function ($http, $window, ngToast) {
return; return;
} }
this.updateShowHue = function () {
this.state.showHue = self.state.settings.hueconfigured;
return;
}
this.updateShowHal = function () {
this.state.showHal = self.state.settings.halconfigured;
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 +182,8 @@ app.service('bridgeService', function ($http, $window, ngToast) {
self.updateShowVera(); self.updateShowVera();
self.updateShowHarmony(); self.updateShowHarmony();
self.updateShowNest(); self.updateShowNest();
self.updateShowHue();
self.updateShowHal();
}, },
function (error) { function (error) {
self.displayWarn("Load Bridge Settings Error: ", error); self.displayWarn("Load Bridge Settings Error: ", error);
@@ -211,6 +248,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;
@@ -263,6 +313,19 @@ app.service('bridgeService', function ($http, $window, ngToast) {
); );
}; };
this.viewHalDevices = function () {
if(!this.state.showHal)
return;
return $http.get(this.state.base + "/hal/devices").then(
function (response) {
self.state.haldevices = response.data;
},
function (error) {
self.displayWarn("Get Hal Devices Error: ", error);
}
);
};
this.updateLogLevels = function(logComponents) { this.updateLogLevels = function(logComponents) {
return $http.put(this.state.systemsbase + "/logmgmt/update", logComponents ).then( return $http.put(this.state.systemsbase + "/logmgmt/update", logComponents ).then(
function (response) { function (response) {
@@ -295,6 +358,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);
@@ -535,7 +599,7 @@ app.controller('SystemController', function ($scope, $location, $http, $window,
bridgeService.viewConfigs(); bridgeService.viewConfigs();
$scope.bridge = bridgeService.state; $scope.bridge = bridgeService.state;
$scope.optionalbackupname = ""; $scope.optionalbackupname = "";
$scope.isInControl = false; $scope.bridge.isInControl = false;
$scope.visible = false; $scope.visible = false;
$scope.imgUrl = "glyphicon glyphicon-plus"; $scope.imgUrl = "glyphicon glyphicon-plus";
$scope.addVeratoSettings = function (newveraname, newveraip) { $scope.addVeratoSettings = function (newveraname, newveraip) {
@@ -570,21 +634,47 @@ 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.addHaltoSettings = function (newhalname, newhalip) {
if($scope.bridge.settings.haladdress == null) {
$scope.bridge.settings.haladdress = { devices: [] };
}
var newhal = {name: newhalname, ip: newhalip }
$scope.bridge.settings.haladdress.devices.push(newhal);
$scope.newhalname = null;
$scope.newhalip = null;
};
$scope.removeHaltoSettings = function (halname, halip) {
for(var i = $scope.bridge.settings.haladdress.devices.length - 1; i >= 0; i--) {
if($scope.bridge.settings.haladdress.devices[i].name === halname && $scope.bridge.settings.haladdress.devices[i].ip === halip) {
$scope.bridge.settings.haladdress.devices.splice(i, 1);
}
}
};
$scope.bridgeReinit = function () { $scope.bridgeReinit = function () {
$scope.isInControl = false;
bridgeService.reinit(); bridgeService.reinit();
}; };
$scope.bridgeStop = function () { $scope.bridgeStop = function () {
$scope.isInControl = false;
bridgeService.stop(); bridgeService.stop();
}; };
$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 +752,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 +773,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,11 +843,49 @@ 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();
if(mapandid.mapType == "veraDevice")
bridgeService.viewVeraDevices();
if(mapandid.mapType == "veraScene")
bridgeService.viewVeraScenes();
if(mapandid.mapType == "harmonyActivity")
bridgeService.viewHarmonyActivities();
if(mapandid.mapType == "harmonyButton")
bridgeService.viewHarmonyDevices();
if(mapandid.mapType == "nestThermoSet" || mapandid.mapType == "nestHomeAway")
bridgeService.viewNestItems();
if(mapandid.mapType == "hueDevice")
bridgeService.viewHueDevices();
if(mapandid.mapType == "halDevice")
bridgeService.viewHalDevices();
$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 = "";
$scope.bulk = { devices: [] }; $scope.bulk = { devices: [] };
$scope.selectAll = false;
var veraList = angular.fromJson($scope.bridge.settings.veraaddress); var veraList = angular.fromJson($scope.bridge.settings.veraaddress);
if(veraList != null) if(veraList != null)
$scope.vera = {base: "http://" + veraList.devices[0].ip, port: "3480", id: ""}; $scope.vera = {base: "http://" + veraList.devices[0].ip, port: "3480", id: ""};
@@ -835,7 +970,9 @@ app.controller('VeraController', function ($scope, $location, $http, bridgeServi
deviceType: $scope.device.deviceType, deviceType: $scope.device.deviceType,
targetDevice: $scope.device.targetDevice, targetDevice: $scope.device.targetDevice,
onUrl: $scope.device.onUrl, onUrl: $scope.device.onUrl,
dimUrl: $scope.device.dimUrl,
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,
@@ -844,12 +981,19 @@ app.controller('VeraController', function ($scope, $location, $http, bridgeServi
} }
} }
} }
bridgeService.bulkAddDevice(devicesList); bridgeService.bulkAddDevice(devicesList).then(
function () {
$scope.clearDevice(); $scope.clearDevice();
bridgeService.viewDevices(); bridgeService.viewDevices();
bridgeService.viewVeraDevices(); bridgeService.viewVeraDevices();
bridgeService.viewVeraScenes(); bridgeService.viewVeraScenes();
},
function (error) {
bridgeService.displayWarn("Error adding Vera devices in bulk.", error)
}
);
$scope.bulk = { devices: [] }; $scope.bulk = { devices: [] };
$scope.selectAll = false;
}; };
$scope.toggleSelection = function toggleSelection(deviceId) { $scope.toggleSelection = function toggleSelection(deviceId) {
@@ -858,11 +1002,28 @@ app.controller('VeraController', function ($scope, $location, $http, bridgeServi
// is currently selected // is currently selected
if (idx > -1) { if (idx > -1) {
$scope.bulk.devices.splice(idx, 1); $scope.bulk.devices.splice(idx, 1);
if($scope.bulk.devices.length == 0 && $scope.selectAll)
$scope.selectAll = false;
} }
// is newly selected // is newly selected
else { else {
$scope.bulk.devices.push(deviceId); $scope.bulk.devices.push(deviceId);
$scope.selectAll = true;
}
};
$scope.toggleSelectAll = function toggleSelectAll() {
if($scope.selectAll) {
$scope.selectAll = false;
$scope.bulk = { devices: [] };
}
else {
$scope.selectAll = true;
for(var x = 0; x < bridgeService.state.veradevices.length; x++) {
if($scope.bulk.devices.indexOf(bridgeService.state.veradevices[x]) < 0 && !bridgeService.findDeviceByMapId(bridgeService.state.veradevices[x].id, bridgeService.state.veradevices[x].veraname, "veraDevice"))
$scope.bulk.devices.push(bridgeService.state.veradevices[x].id);
}
} }
}; };
@@ -875,15 +1036,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();
@@ -907,21 +1070,22 @@ app.controller('HarmonyController', function ($scope, $location, $http, bridgeSe
}; };
$scope.buildButtonUrls = function (harmonydevice, onbutton, offbutton) { $scope.buildButtonUrls = function (harmonydevice, onbutton, offbutton) {
bridgeService.clearDevice();
var currentOn = $scope.device.onUrl; var currentOn = $scope.device.onUrl;
var currentOff = $scope.device.offUrl; var currentOff = $scope.device.offUrl;
var actionOn = angular.fromJson(onbutton); var actionOn = angular.fromJson(onbutton);
var actionOff = angular.fromJson(offbutton); var actionOff = angular.fromJson(offbutton);
if( $scope.device.mapType == "harmonyButton") { if( $scope.device.mapType == "harmonyButton") {
$scope.device.mapId = $scope.device.mapId + "-" + actionOn.command;
$scope.device.onUrl = currentOn.substr(0, currentOn.indexOf("]")) + ",{\"device\":\"" + harmonydevice.device.id + "\",\"button\":\"" + actionOn.command + "\"}]"; $scope.device.onUrl = currentOn.substr(0, currentOn.indexOf("]")) + ",{\"device\":\"" + harmonydevice.device.id + "\",\"button\":\"" + actionOn.command + "\"}]";
$scope.device.offUrl = currentOff.substr(0, currentOff.indexOf("]")) + ",{\"device\":\"" + harmonydevice.device.id + "\",\"button\":\"" + actionOff.command + "\"}]"; $scope.device.offUrl = currentOff.substr(0, currentOff.indexOf("]")) + ",{\"device\":\"" + harmonydevice.device.id + "\",\"button\":\"" + actionOff.command + "\"}]";
} }
else if ($scope.device.mapType == null || $scope.device.mapType == "") { else if ($scope.device.mapType == null || $scope.device.mapType == "") {
bridgeService.clearDevice();
$scope.device.deviceType = "button"; $scope.device.deviceType = "button";
$scope.device.targetDevice = harmonydevice.hub; $scope.device.targetDevice = harmonydevice.hub;
$scope.device.name = harmonydevice.device.label; $scope.device.name = harmonydevice.device.label;
$scope.device.mapType = "harmonyButton"; $scope.device.mapType = "harmonyButton";
$scope.device.mapId = harmonydevice.device.id + "-" + actionOn.command + "-" + actionOff.command; $scope.device.mapId = harmonydevice.device.id + "-" + actionOn.command;
$scope.device.onUrl = "[{\"device\":\"" + harmonydevice.device.id + "\",\"button\":\"" + actionOn.command + "\"}]"; $scope.device.onUrl = "[{\"device\":\"" + harmonydevice.device.id + "\",\"button\":\"" + actionOn.command + "\"}]";
$scope.device.offUrl = "[{\"device\":\"" + harmonydevice.device.id + "\",\"button\":\"" + actionOff.command + "\"}]"; $scope.device.offUrl = "[{\"device\":\"" + harmonydevice.device.id + "\",\"button\":\"" + actionOff.command + "\"}]";
} }
@@ -952,15 +1116,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 +1238,460 @@ 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: [] };
$scope.selectAll = false;
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.viewDevices();
bridgeService.viewNestItems(); 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,
dimUrl: $scope.device.dimUrl,
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).then(
function () {
$scope.clearDevice();
bridgeService.viewDevices();
bridgeService.viewHueDevices();
},
function (error) {
bridgeService.displayWarn("Error adding Hue devices in bulk.", error)
}
);
$scope.bulk = { devices: [] };
$scope.selectAll = false;
};
$scope.toggleSelection = function toggleSelection(deviceId) {
var idx = $scope.bulk.devices.indexOf(deviceId);
// is currently selected
if (idx > -1) {
$scope.bulk.devices.splice(idx, 1);
if($scope.bulk.devices.length == 0 && $scope.selectAll)
$scope.selectAll = false;
}
// is newly selected
else {
$scope.bulk.devices.push(deviceId);
$scope.selectAll = true;
}
};
$scope.toggleSelectAll = function toggleSelectAll() {
if($scope.selectAll) {
$scope.selectAll = false;
$scope.bulk = { devices: [] };
}
else {
$scope.selectAll = true;
for(var x = 0; x < bridgeService.state.huedevices.length; x++) {
if($scope.bulk.devices.indexOf(bridgeService.state.huedevices[x]) < 0 && !bridgeService.findDeviceByMapId(bridgeService.state.huedevices[x].device.uniqueid, bridgeService.state.huedevices[x].huename, "hueDevice"))
$scope.bulk.devices.push(bridgeService.state.huedevices[x].device.uniqueid);
}
}
};
$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'
});
};
});
app.controller('HalController', function ($scope, $location, $http, bridgeService, ngDialog) {
$scope.bridge = bridgeService.state;
$scope.device = $scope.bridge.device;
$scope.device_dim_control = "";
$scope.bulk = { devices: [] };
$scope.selectAll = false;
bridgeService.viewHalDevices();
$scope.imgButtonsUrl = "glyphicon glyphicon-plus";
$scope.buttonsVisible = false;
$scope.clearDevice = function () {
bridgeService.clearDevice();
};
$scope.buildDeviceUrls = function (haldevice, dim_control) {
bridgeService.clearDevice();
$scope.device = $scope.bridge.device;
var preOnCmd = "";
var preDimCmd = "";
var preOffCmd = "";
var nameCmd = ""
var postCmd = "?Token=" + $scope.bridge.settings.haltoken;
if(haldevice.haldevicetype == "Group") {
$scope.device.deviceType = "group";
preOnCmd = "/GroupService!GroupCmd=On";
preOffCmd = "/GroupService!GroupCmd=Off";
nameCmd = "!GroupName=";
}
else if(haldevice.haldevicetype == "Macro") {
$scope.device.deviceType = "macro";
preOnCmd = "/MacroService!MacroCmd=Set!MacroName=";
preOffCmd = preOnCmd;
}
else if(haldevice.haldevicetype == "Scene") {
$scope.device.deviceType = "scene";
preOnCmd = "/SceneService!SceneCmd=Set!SceneName=";
preOffCmd = preOnCmd;
}
else {
$scope.device.deviceType = "switch";
preOnCmd = "/DeviceService!DeviceCmd=SetDevice!DeviceValue=On";
preDimCmd = "/DeviceService!DeviceCmd=SetDevice!DeviceValue=Dim!DevicePercent=";
preOffCmd = "/DeviceService!DeviceCmd=SetDevice!DeviceValue=Off";
nameCmd = "!DeviceName=";
}
$scope.device.name = haldevice.haldevicename;
$scope.device.targetDevice = haldevice.halname;
$scope.device.mapType = "halDevice";
$scope.device.mapId = haldevice.haldevicename + "-" + haldevice.halname;
if((dim_control.indexOf("byte") >= 0 || dim_control.indexOf("percent") >= 0 || dim_control.indexOf("math") >= 0) && $scope.device.deviceType == "switch")
$scope.device.dimUrl = "http://" + haldevice.haladdress
+ preDimCmd
+ dim_control
+ nameCmd
+ haldevice.haldevicename.replaceAll(" ", "%20")
+ postCmd;
else
$scope.device.dimUrl = "http://" + haldevice.haladdress
+ preOnCmd
+ nameCmd
+ haldevice.haldevicename.replaceAll(" ", "%20")
+ postCmd;
$scope.device.onUrl = "http://" + haldevice.haladdress
+ preOnCmd
+ nameCmd
+ haldevice.haldevicename.replaceAll(" ", "%20")
+ postCmd;
$scope.device.offUrl = "http://" + haldevice.haladdress
+ preOffCmd
+ nameCmd
+ haldevice.haldevicename.replaceAll(" ", "%20")
+ postCmd;
};
$scope.buildButtonUrls = function (haldevice, onbutton, offbutton) {
var currentOn = $scope.device.onUrl;
var currentOff = $scope.device.offUrl;
var actionOn = angular.fromJson(onbutton);
var actionOff = angular.fromJson(offbutton);
if( $scope.device.mapType == "halButton") {
$scope.device.mapId = $scope.device.mapId + "-" + actionOn.DeviceName;
$scope.device.onUrl = currentOn.substr(0, currentOn.indexOf("]")) + ",{\"item\":\"http://" + haldevice.haladdress + "/IrService!IrCmd=Set!IrDevice=" + haldevice.haldevicename.replaceAll(" ", "%20") + "!IrButton=" + actionOn.DeviceName.replaceAll(" ", "%20") + "?Token=" + $scope.bridge.settings.haltoken +"\"}]";
$scope.device.offUrl = currentOff.substr(0, currentOff.indexOf("]")) + ",{\"item\":\"http://" + haldevice.haladdress + "/IrService!IrCmd=Set!IrDevice=" + haldevice.haldevicename.replaceAll(" ", "%20") + "!IrButton=" + actionOff.DeviceName.replaceAll(" ", "%20") + "?Token=" + $scope.bridge.settings.haltoken + "\"}]";
}
else if ($scope.device.mapType == null || $scope.device.mapType == "") {
bridgeService.clearDevice();
$scope.device.deviceType = "button";
$scope.device.targetDevice = haldevice.halname;
$scope.device.name = haldevice.haldevicename;
$scope.device.mapType = "halButton";
$scope.device.mapId = haldevice.haldevicename + "-" + haldevice.halname + "-" + actionOn.DeviceName;
$scope.device.onUrl = "[{\"item\":\"http://" + haldevice.haladdress + "/IrService!IrCmd=Set!IrDevice=" + haldevice.haldevicename.replaceAll(" ", "%20") + "!IrButton=" + actionOn.DeviceName.replaceAll(" ", "%20") + "?Token=" + $scope.bridge.settings.haltoken + "\"}]";
$scope.device.offUrl = "[{\"item\":\"http://" + haldevice.haladdress + "/IrService!IrCmd=Set!IrDevice=" + haldevice.haldevicename.replaceAll(" ", "%20") + "!IrButton=" + actionOff.DeviceName.replaceAll(" ", "%20") + "?Token=" + $scope.bridge.settings.haltoken + "\"}]";
}
};
$scope.buildHALHomeUrls = function (haldevice) {
bridgeService.clearDevice();
$scope.device.deviceType = "home";
$scope.device.name = haldevice.haldevicename;
$scope.device.targetDevice = haldevice.halname;
$scope.device.mapType = "halHome";
$scope.device.mapId = haldevice.haldevicename + "-" + haldevice.halname + "-HomeAway";
$scope.device.onUrl = "http://" + haldevice.haladdress + "/ModeService!ModeCmd=Set!ModeName=Home?Token=" + $scope.bridge.settings.haltoken;
$scope.device.offUrl = "http://" + haldevice.haladdress + "/ModeService!ModeCmd=Set!ModeName=Away?Token=" + $scope.bridge.settings.haltoken;
};
$scope.buildHALHeatUrls = function (haldevice) {
bridgeService.clearDevice();
$scope.device.deviceType = "thermo";
$scope.device.name = haldevice.haldevicename + " Heat";
$scope.device.targetDevice = haldevice.halname;
$scope.device.mapType = "halThermoSet";
$scope.device.mapId = haldevice.haldevicename + "-" + haldevice.halname + "-SetHeat";
$scope.device.onUrl = "http://" + haldevice.haladdress
+ "/HVACService!HVACCmd=Set!HVACName="
+ haldevice.haldevicename.replaceAll(" ", "%20")
+ "!HVACMode=Heat?Token="
+ $scope.bridge.settings.haltoken;
$scope.device.dimUrl = "http://" + haldevice.haladdress
+ "/HVACService!HVACCmd=Set!HVACName="
+ haldevice.haldevicename.replaceAll(" ", "%20")
+ "!HVACMode=Heat!HeatSpValue=${intensity.percent}?Token="
+ $scope.bridge.settings.haltoken;
$scope.device.offUrl = "http://" + haldevice.haladdress
+ "/HVACService!HVACCmd=Set!HVACName="
+ haldevice.haldevicename.replaceAll(" ", "%20")
+ "!HVACMode=Off?Token="
};
$scope.buildHALCoolUrls = function (haldevice) {
bridgeService.clearDevice();
$scope.device.deviceType = "thermo";
$scope.device.name = haldevice.haldevicename + " Cool";
$scope.device.targetDevice = haldevice.halname;
$scope.device.mapType = "halThermoSet";
$scope.device.mapId = haldevice.haldevicename + "-" + haldevice.halname + "-SetCool";
$scope.device.onUrl = "http://" + haldevice.haladdress
+ "/HVACService!HVACCmd=Set!HVACName="
+ haldevice.haldevicename.replaceAll(" ", "%20")
+ "!HVACMode=Cool?Token="
+ $scope.bridge.settings.haltoken;
$scope.device.dimUrl = "http://" + haldevice.haladdress
+ "/HVACService!HVACCmd=Set!HVACName="
+ haldevice.haldevicename.replaceAll(" ", "%20")
+ "!HVACMode=Cool!CoolSpValue=${intensity.percent}?Token="
+ $scope.bridge.settings.haltoken;
$scope.device.offUrl = "http://" + haldevice.haladdress
+ "/HVACService!HVACCmd=Set!HVACName="
+ haldevice.haldevicename.replaceAll(" ", "%20")
+ "!HVACMode=Off?Token="
};
$scope.buildHALAutoUrls = function (haldevice) {
bridgeService.clearDevice();
$scope.device.deviceType = "thermo";
$scope.device.name = haldevice.haldevicename + " Auto";
$scope.device.targetDevice = haldevice.halname;
$scope.device.mapType = "halThermoSet";
$scope.device.mapId = haldevice.haldevicename + "-" + haldevice.halname + "-SetAuto";
$scope.device.onUrl = "http://" + haldevice.haladdress
+ "/HVACService!HVACCmd=Set!HVACName="
+ haldevice.haldevicename.replaceAll(" ", "%20")
+ "!HVACMode=Auto?Token="
+ $scope.bridge.settings.haltoken;
$scope.device.offUrl = "http://" + haldevice.haladdress
+ "/HVACService!HVACCmd=Set!HVACName="
+ haldevice.haldevicename.replaceAll(" ", "%20")
+ "!HVACMode=Off?Token="
};
$scope.buildHALOffUrls = function (haldevice) {
bridgeService.clearDevice();
$scope.device.deviceType = "thermo";
$scope.device.name = haldevice.haldevicename + " Thermostat";
$scope.device.targetDevice = haldevice.halname;
$scope.device.mapType = "halThermoSet";
$scope.device.mapId = haldevice.haldevicename + "-" + haldevice.halname + "-TurnOff";
$scope.device.onUrl = "http://" + haldevice.haladdress
+ "/HVACService!HVACCmd=Set!HVACName="
+ haldevice.haldevicename.replaceAll(" ", "%20")
+ "!HVACMode=Auto?Token="
+ $scope.bridge.settings.haltoken;
$scope.device.offUrl = "http://" + haldevice.haladdress
+ "/HVACService!HVACCmd=Set!HVACName="
+ haldevice.haldevicename.replaceAll(" ", "%20")
+ "!HVACMode=Off?Token="
};
$scope.buildHALFanUrls = function (haldevice) {
bridgeService.clearDevice();
$scope.device.deviceType = "thermo";
$scope.device.name = haldevice.haldevicename + " Fan";
$scope.device.targetDevice = haldevice.halname;
$scope.device.mapType = "halThermoSet";
$scope.device.mapId = haldevice.haldevicename + "-" + haldevice.halname + "-SetFan";
$scope.device.onUrl = "http://" + haldevice.haladdress
+ "/HVACService!HVACCmd=Set!HVACName="
+ haldevice.haldevicename.replaceAll(" ", "%20")
+ "!FanMode=On?Token="
+ $scope.bridge.settings.haltoken;
$scope.device.offUrl = "http://" + haldevice.haladdress
+ "/HVACService!HVACCmd=Set!HVACName="
+ haldevice.haldevicename.replaceAll(" ", "%20")
+ "!FanMode=Auto?Token="
+ $scope.bridge.settings.haltoken;
};
$scope.addDevice = function () {
if($scope.device.name == "" && $scope.device.onUrl == "")
return;
bridgeService.addDevice($scope.device).then(
function () {
$scope.clearDevice();
bridgeService.viewDevices();
bridgeService.viewHalDevices();
},
function (error) {
bridgeService.displayWarn("Error adding device: " + $scope.device.name, error)
}
);
};
$scope.bulkAddDevices = function(dim_control) {
var devicesList = [];
for(var i = 0; i < $scope.bulk.devices.length; i++) {
for(var x = 0; x < bridgeService.state.haldevices.length; x++) {
if(bridgeService.state.haldevices[x].haldevicename == $scope.bulk.devices[i]) {
if(bridgeService.state.haldevices[x].haldevicetype == "HVAC")
$scope.buildHALAutoUrls(bridgeService.state.haldevices[x]);
else if(bridgeService.state.haldevices[x].haldevicetype == "HOME")
$scope.buildHALHomeUrls(bridgeService.state.haldevices[x]);
else
$scope.buildDeviceUrls(bridgeService.state.haldevices[x],dim_control);
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,
dimUrl: $scope.device.dimUrl,
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).then(
function () {
$scope.clearDevice();
bridgeService.viewDevices();
bridgeService.viewHalDevices();
},
function (error) {
bridgeService.displayWarn("Error adding HAL devices in bulk.", error)
}
);
$scope.bulk = { devices: [] };
$scope.selectAll = false;
};
$scope.toggleSelection = function toggleSelection(deviceId) {
var idx = $scope.bulk.devices.indexOf(deviceId);
// is currently selected
if (idx > -1) {
$scope.bulk.devices.splice(idx, 1);
if($scope.bulk.devices.length == 0 && $scope.selectAll)
$scope.selectAll = false;
}
// is newly selected
else {
$scope.bulk.devices.push(deviceId);
$scope.selectAll = true;
}
};
$scope.toggleSelectAll = function toggleSelectAll() {
if($scope.selectAll) {
$scope.selectAll = false;
$scope.bulk = { devices: [] };
}
else {
$scope.selectAll = true;
for(var x = 0; x < bridgeService.state.haldevices.length; x++) {
if($scope.bulk.devices.indexOf(bridgeService.state.haldevices[x]) < 0 && !bridgeService.findDeviceByMapId(bridgeService.state.haldevices[x].haldevicename + "-" + bridgeService.state.haldevices[x].halname, bridgeService.state.haldevices[x].halname, "halDevice"))
$scope.bulk.devices.push(bridgeService.state.haldevices[x].haldevicename);
}
}
};
$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 +1899,63 @@ 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('availableHalDeviceId', 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].haldevicename + "-" + input[i].halname, input[i].halname, "halDevice") &&
!bridgeService.findDeviceByMapId(input[i].haldevicename + "-" + input[i].halname + "-HomeAway", input[i].halname, "halHome") ){
out.push(input[i]);
}
}
return out;
}
});
app.filter('unavailableHalDeviceId', function(bridgeService) {
return function(input) {
var out = [];
if(input == null)
return out;
for (var i = 0; i < input.length; i++) {
if(input[i].mapType != null && bridgeService.aContainsB(input[i].mapType, "hal")){
out.push(input[i]);
}
}
return out;
}
});
app.filter('configuredButtons', function() { app.filter('configuredButtons', function() {
return function(input) { return function(input) {
var out = []; var out = [];

View File

@@ -1,18 +1,29 @@
<ul class="nav nav-pills" role="tablist"> <ul class="nav nav-pills" role="tablist">
<li role="presentation" class="active"><a href="#">Bridge Devices</a></li> <li role="presentation" class="active"><a href="#">Bridge
Devices</a></li>
<li role="presentation"><a href="#/system">Bridge Control</a></li> <li role="presentation"><a href="#/system">Bridge Control</a></li>
<li role="presentation"><a href="#/logs">Logs</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
<li ng-if="bridge.showVera" role="presentation"><a href="#/verascenes">Vera Scenes</a></li> href="#/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li> <li ng-if="bridge.showVera" role="presentation"><a
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li> 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 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 ng-if="bridge.showHal" role="presentation"><a
href="#/haldevices">HAL 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"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<h2 class="panel-title">Current devices ({{bridge.devices.length}}) </h2> <h2 class="panel-title">Current devices
({{bridge.devices.length}})</h2>
</div> </div>
<scrollable-table watch="bridge.devices"> <scrollable-table watch="bridge.devices">
<table class="table table-bordered table-striped table-hover"> <table class="table table-bordered table-striped table-hover">
@@ -50,21 +61,27 @@
</table> </table>
</scrollable-table> </scrollable-table>
</div> </div>
<div class="panel panel-default backup"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<h1 class="panel-title">Bridge Device DB Backup <a ng-click="toggleBk()"><span class={{imgBkUrl}} aria-hidden="true"></a></h1> <h1 class="panel-title">
Bridge Device DB Backup <a ng-click="toggleBk()"><span
class={{imgBkUrl}} aria-hidden="true"></a>
</h1>
</div> </div>
<div ng-if="visibleBk" class="animate-if" class="panel-body"> <div ng-if="visibleBk" class="animate-if" class="panel-body">
<p>Control your backups from this area. Use the default name by hitting backup or specify your own.</p>
<form class="form-horizontal"> <form class="form-horizontal">
<div class="form-group"> <div class="form-group">
<label class="col-xs-12 col-sm-2 control-label" for="backup-name">Backup File Name</label> <label class="col-xs-12 col-sm-2 control-label" for="backup-name">Backup
File Name</label>
<div class="col-xs-8 col-sm-7"> <div class="col-xs-8 col-sm-7">
<input id="backup-name" class="form-control" type="text" <input id="backup-name" class="form-control" type="text"
ng-model="optionalbackupname" placeholder="Optional"> ng-model="optionalbackupname" placeholder="Optional">
</div> </div>
<button type="submit" class="btn btn-primary" <button type="submit" class="btn btn-primary"
ng-click="backupDeviceDb(optionalbackupname)">Backup Device DB</button> ng-click="backupDeviceDb(optionalbackupname)">Backup
Device DB</button>
</div> </div>
</form> </form>
<table class="table table-bordered table-striped table-hover"> <table class="table table-bordered table-striped table-hover">
@@ -102,4 +119,13 @@
<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>

View File

@@ -2,24 +2,36 @@
<li role="presentation"><a href="#">Bridge Devices</a></li> <li role="presentation"><a href="#">Bridge Devices</a></li>
<li role="presentation"><a href="#/system">Bridge Control</a></li> <li role="presentation"><a href="#/system">Bridge Control</a></li>
<li role="presentation"><a href="#/logs">Logs</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
<li ng-if="bridge.showVera" role="presentation"><a href="#/verascenes">Vera Scenes</a></li> href="#/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li> <li ng-if="bridge.showVera" role="presentation"><a
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li> 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 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 ng-if="bridge.showHal" role="presentation"><a
href="#/haldevices">HAL Devices</a></li>
<li role="presentation" class="active"><a href="#/editdevice">Edit
Device</a></li>
</ul> </ul>
<div class="panel panel-default bridgeServer" ng-if="!bridge.error"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<h2 class="panel-title">Edit/Copy a device</h2> <h2 class="panel-title">Edit/Copy a device</h2>
</div> </div>
<p class="text-muted">This screen allows the modification of many fields the bridge uses. Please use care when <div class="panel-body">
updating these fields as you may break the settings used by the bridge to call a specific end point device.</p> <p class="text-muted">This screen allows the modification of many
<p>When copying, update the name and select the "Add Bridge Device" Button.</p> fields the bridge uses. Please use care when updating these fields as
<ul class="list-group"> you may break the settings used by the bridge to call a specific end
<li class="list-group-item"> point device.</p>
<p>When copying, update the name and select the "Add Bridge
Device" Button.</p>
</div>
<form class="form-horizontal"> <form class="form-horizontal">
<div class="form-group"> <div class="form-group">
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name <label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
@@ -29,8 +41,8 @@
<input type="text" class="form-control" id="device-name" <input type="text" class="form-control" id="device-name"
ng-model="device.name" placeholder="Device Name"> ng-model="device.name" placeholder="Device Name">
</div> </div>
<button type="submit" class="col-xs-4 col-sm-2 btn btn-success" ng-click="addDevice()"> <button type="submit" class="col-xs-4 col-sm-2 btn btn-success"
Update Bridge Device</button> ng-click="addDevice()">Update Bridge Device</button>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="col-xs-12 col-sm-2 control-label" for="device-target">Target <label class="col-xs-12 col-sm-2 control-label" for="device-target">Target
@@ -40,23 +52,55 @@
<input type="text" class="form-control" id="device-target" <input type="text" class="form-control" id="device-target"
ng-model="device.targetDevice" placeholder="default"> ng-model="device.targetDevice" placeholder="default">
</div> </div>
<button class="btn btn-primary" ng-click="copyDevice()"> <button class="btn btn-primary" ng-click="copyDevice()">Add
Add Bridge Device</button> Bridge Device</button>
</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-type">Device
</label> Type </label>
<div class="col-xs-8 col-sm-7"> <div class="col-xs-8 col-sm-7">
<select name="device-map-type" id="device-map-type" ng-model="device.mapType"> <select name="device-type" id="device-type"
<option value="">---Please select---</option> <!-- not selected / blank option --> 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="macro">Macro</option>
<option value="group">Group</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="row">
<label class="col-xs-12 col-sm-2 control-label"
for="device-map-type">Map Type </label>
<div class="col-xs-8 col-sm-7">
<select name="device-map-type" id="device-map-type"
ng-model="device.mapType">
<option value="">---Please select---</option>
<!-- not selected / blank option -->
<option value="veraDevice">Vera Device</option> <option value="veraDevice">Vera Device</option>
<option value="veraScene">Vera Scene</option> <option value="veraScene">Vera Scene</option>
<option value="harmonyActivity">Harmony Activity</option> <option value="harmonyActivity">Harmony Activity</option>
<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>
<option value="halDevice">HAL Device</option>
<option value="halHome">HAL Home Status</option>
<option value="halThermoSet">HAL Thermostat</option>
</select> </select>
</div> </div>
<button class="btn btn-danger" ng-click="clearDevice()"> <button class="btn btn-danger" ng-click="clearDevice()">
@@ -64,8 +108,8 @@
</div> </div>
</div> </div>
<div ng-if="device.mapType" class="form-group"> <div ng-if="device.mapType" class="form-group">
<label class="col-xs-12 col-sm-2 control-label" for="device-map-id">Map ID <label class="col-xs-12 col-sm-2 control-label" for="device-map-id">Map
</label> ID </label>
<div class="col-xs-8 col-sm-7"> <div class="col-xs-8 col-sm-7">
<input type="text" class="form-control" id="device-map-id" <input type="text" class="form-control" id="device-map-id"
@@ -96,8 +140,8 @@
</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" <label class="col-xs-12 col-sm-2 control-label" for="device-off-url">Off
for="device-off-url">Off URL </label> URL </label>
<div class="col-xs-8 col-sm-7"> <div class="col-xs-8 col-sm-7">
<textarea rows="3" class="form-control" id="device-off-url" <textarea rows="3" class="form-control" id="device-off-url"
@@ -107,12 +151,26 @@
</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-headers">HTTP
</label> Headers </label>
<div class="col-xs-8 col-sm-7"> <div class="col-xs-8 col-sm-7">
<select name="device-http-verb" id="device-http-verb" ng-model="device.httpVerb"> <textarea rows="3" class="form-control" id="device-headers"
<option value="">---Please select---</option> <!-- not selected / blank option --> ng-model="device.headers"
placeholder="format like: [{&quot;name&quot;:&quot;A name&quot;,&quot;value&quot;:&quot;a value&quot;}]"></textarea>
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<label class="col-xs-12 col-sm-2 control-label"
for="device-http-verb">Http Verb </label>
<div class="col-xs-8 col-sm-7">
<select name="device-http-verb" id="device-http-verb"
ng-model="device.httpVerb">
<option value="">---Please select---</option>
<!-- not selected / blank option -->
<option value="GET">GET</option> <option value="GET">GET</option>
<option value="PUT">PUT</option> <option value="PUT">PUT</option>
<option value="POST">POST</option> <option value="POST">POST</option>
@@ -122,12 +180,14 @@
</div> </div>
<div ng-if="device.httpVerb" class="form-group"> <div ng-if="device.httpVerb" class="form-group">
<div class="row"> <div class="row">
<label class="col-xs-12 col-sm-2 control-label" for="device-content-type">Content Type <label class="col-xs-12 col-sm-2 control-label"
</label> for="device-content-type">Content Type </label>
<div class="col-xs-8 col-sm-7"> <div class="col-xs-8 col-sm-7">
<select name="device-content-type" id="device-content-type" ng-model="device.contentType"> <select name="device-content-type" id="device-content-type"
<option value="">---Please select---</option> <!-- not selected / blank option --> ng-model="device.contentType">
<option value="">---Please select---</option>
<!-- not selected / blank option -->
<option value="application/atom+xml">application/atom+xml</option> <option value="application/atom+xml">application/atom+xml</option>
<option value="application/x-www-form-urlencoded">application/x-www-form-urlencoded</option> <option value="application/x-www-form-urlencoded">application/x-www-form-urlencoded</option>
<option value="application/json">application/json</option> <option value="application/json">application/json</option>
@@ -152,7 +212,8 @@
<div class="col-xs-8 col-sm-7"> <div class="col-xs-8 col-sm-7">
<textarea rows="3" class="form-control" id="device-content-body" <textarea rows="3" class="form-control" id="device-content-body"
ng-model="device.contentBody" placeholder="Content Body On for specific GET/PUT/POST type"></textarea> ng-model="device.contentBody"
placeholder="Content Body On for specific GET/PUT/POST type"></textarea>
</div> </div>
<div class="clearfix visible-xs"></div> <div class="clearfix visible-xs"></div>
</div> </div>
@@ -163,13 +224,12 @@
for="device-content-body-off">Content Body Off</label> for="device-content-body-off">Content Body Off</label>
<div class="col-xs-8 col-sm-7"> <div class="col-xs-8 col-sm-7">
<textarea rows="3" class="form-control" id="device-content-body-off" <textarea rows="3" class="form-control"
ng-model="device.contentBodyOff" placeholder="Content Body Off for specific GET/PUT/POST type"></textarea> id="device-content-body-off" ng-model="device.contentBodyOff"
placeholder="Content Body Off for specific GET/PUT/POST type"></textarea>
</div> </div>
<div class="clearfix visible-xs"></div> <div class="clearfix visible-xs"></div>
</div> </div>
</div> </div>
</form> </form>
</li>
</ul>
</div> </div>

View File

@@ -2,24 +2,32 @@
<li role="presentation"><a href="#">Bridge Devices</a></li> <li role="presentation"><a href="#">Bridge Devices</a></li>
<li role="presentation"><a href="#/system">Bridge Control</a></li> <li role="presentation"><a href="#/system">Bridge Control</a></li>
<li role="presentation"><a href="#/logs">Logs</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
<li ng-if="bridge.showVera" role="presentation"><a href="#/verascenes">Vera Scenes</a></li> href="#/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li> <li ng-if="bridge.showVera" role="presentation"><a
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li> 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 ng-if="bridge.showNest" role="presentation"><a href="#/nest">Nest</a></li>
<li role="presentation" class="active"><a href="#/editor">Manual Add</a></li> <li ng-if="bridge.showHue" role="presentation"><a
href="#/huedevices">Hue Devices</a></li>
<li ng-if="bridge.showHal" role="presentation"><a
href="#/haldevices">HAL Devices</a></li>
<li role="presentation" class="active"><a href="#/editor">Manual
Add</a></li>
</ul> </ul>
<div class="panel panel-default bridgeServer" ng-if="bridge.showVera"> <div ng-if="bridge.showVera" class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<h2 class="panel-title">Generate a new device/scene/control point</h2> <h2 class="panel-title">Generate a new device/scene/control point</h2>
</div> </div>
<ul class="list-group"> <div class="panel-body">
<li class="list-group-item">
<p class="text-muted">You can generate on/off URLs by filling in <p class="text-muted">You can generate on/off URLs by filling in
the Vera server URL, port, and device ID; or you can fill them out the Vera server URL, port, and device ID; or you can fill them out
manually in the lower section.</p> manually in the lower section.</p>
</div>
<form class="form-horizontal"> <form class="form-horizontal">
<div class="form-group"> <div class="form-group">
<label class="col-xs-12 col-sm-2 control-label" for="vera-base">Vera <label class="col-xs-12 col-sm-2 control-label" for="vera-base">Vera
@@ -49,10 +57,12 @@
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="col-xs-2 col-sm-2 control-label" for="device-dim-control">Device Dim Control</label> <label class="col-xs-2 col-sm-2 control-label"
for="device-dim-control">Device Dim Control</label>
<div class="col-xs-10 col-sm-2"> <div class="col-xs-10 col-sm-2">
<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>
@@ -61,25 +71,32 @@
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<button type="submit" ng-click="buildUrlsUsingDevice(device_dim_control)" <button type="submit"
class="col-xs-2 col-sm-2 col-xs-offset-2 col-sm-offset-2 btn btn-success">Generate Device ng-click="buildUrlsUsingDevice(device_dim_control)"
URLs</button> class="col-xs-2 col-sm-2 col-xs-offset-2 col-sm-offset-2 btn btn-success">Generate
Device URLs</button>
<button type="submit" ng-click="buildUrlsUsingScene()" <button type="submit" ng-click="buildUrlsUsingScene()"
class="col-xs-2 col-sm-2 col-xs-offset-2 col-sm-offset-2 btn btn-success">Generate Scene class="col-xs-2 col-sm-2 col-xs-offset-2 col-sm-offset-2 btn btn-success">Generate
URLs</button> Scene URLs</button>
</div> </div>
</form> </form>
</li>
</ul>
</div> </div>
<div class="panel panel-default bridgeServer" ng-if="!bridge.error"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<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 <div class="panel-body">
the http verb type below and configure a payload for either on or off methods. Currently, https is not supported.</p> <p class="text-muted">This area allows you to create any http or
<ul class="list-group"> udp call to an endpoint. You can use the default GET or select the
<li class="list-group-item"> 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 [{&quot;item&quot;:&quot;the
payload&quot;},{&quot;item&quot;:&quot;another payload&quot;}] to
execute multiple entries. Adding the value replacements
(${intensity..byte},${intensity.percent},${intensity.math(X*1)}) will
also work.</p>
</div>
<form class="form-horizontal"> <form class="form-horizontal">
<div class="form-group"> <div class="form-group">
<div class="row"> <div class="row">
@@ -90,8 +107,26 @@
<input type="text" class="form-control" id="device-name" <input type="text" class="form-control" id="device-name"
ng-model="device.name" placeholder="Device Name"> ng-model="device.name" placeholder="Device Name">
</div> </div>
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary" ng-click="addDevice()"> <button type="submit" class="col-xs-4 col-sm-2 btn btn-primary"
Add Bridge Device</button> ng-click="addDevice()">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>
</select>
</div>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
@@ -120,8 +155,8 @@
</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" <label class="col-xs-12 col-sm-2 control-label" for="device-off-url">Off
for="device-off-url">Off URL </label> URL </label>
<div class="col-xs-8 col-sm-7"> <div class="col-xs-8 col-sm-7">
<textarea rows="3" class="form-control" id="device-off-url" <textarea rows="3" class="form-control" id="device-off-url"
@@ -131,12 +166,26 @@
</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-headers">HTTP
</label> Headers </label>
<div class="col-xs-8 col-sm-7"> <div class="col-xs-8 col-sm-7">
<select name="device-http-verb" id="device-http-verb" ng-model="device.httpVerb"> <textarea rows="3" class="form-control" id="device-headers"
<option value="">---Please select---</option> <!-- not selected / blank option --> ng-model="device.headers"
placeholder="format like: [{&quot;name&quot;:&quot;A name&quot;,&quot;value&quot;:&quot;a value&quot;}]"></textarea>
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<label class="col-xs-12 col-sm-2 control-label"
for="device-http-verb">Http Verb </label>
<div class="col-xs-8 col-sm-7">
<select name="device-http-verb" id="device-http-verb"
ng-model="device.httpVerb">
<option value="">---Please select---</option>
<!-- not selected / blank option -->
<option value="GET">GET</option> <option value="GET">GET</option>
<option value="PUT">PUT</option> <option value="PUT">PUT</option>
<option value="POST">POST</option> <option value="POST">POST</option>
@@ -146,12 +195,14 @@
</div> </div>
<div ng-if="device.httpVerb" class="form-group"> <div ng-if="device.httpVerb" class="form-group">
<div class="row"> <div class="row">
<label class="col-xs-12 col-sm-2 control-label" for="device-content-type">Content Type <label class="col-xs-12 col-sm-2 control-label"
</label> for="device-content-type">Content Type </label>
<div class="col-xs-8 col-sm-7"> <div class="col-xs-8 col-sm-7">
<select name="device-content-type" id="device-content-type" ng-model="device.contentType"> <select name="device-content-type" id="device-content-type"
<option value="">---Please select---</option> <!-- not selected / blank option --> ng-model="device.contentType">
<option value="">---Please select---</option>
<!-- not selected / blank option -->
<option value="application/atom+xml">application/atom+xml</option> <option value="application/atom+xml">application/atom+xml</option>
<option value="application/x-www-form-urlencoded">application/x-www-form-urlencoded</option> <option value="application/x-www-form-urlencoded">application/x-www-form-urlencoded</option>
<option value="application/json">application/json</option> <option value="application/json">application/json</option>
@@ -176,7 +227,8 @@
<div class="col-xs-8 col-sm-7"> <div class="col-xs-8 col-sm-7">
<textarea rows="3" class="form-control" id="device-content-body" <textarea rows="3" class="form-control" id="device-content-body"
ng-model="device.contentBody" placeholder="Content Body On for specific GET/PUT/POST type"></textarea> ng-model="device.contentBody"
placeholder="Content Body On for specific GET/PUT/POST type"></textarea>
</div> </div>
<div class="clearfix visible-xs"></div> <div class="clearfix visible-xs"></div>
</div> </div>
@@ -187,13 +239,12 @@
for="device-content-body-off">Content Body Off</label> for="device-content-body-off">Content Body Off</label>
<div class="col-xs-8 col-sm-7"> <div class="col-xs-8 col-sm-7">
<textarea rows="3" class="form-control" id="device-content-body-off" <textarea rows="3" class="form-control"
ng-model="device.contentBodyOff" placeholder="Content Body Off for specific GET/PUT/POST type"></textarea> id="device-content-body-off" ng-model="device.contentBodyOff"
placeholder="Content Body Off for specific GET/PUT/POST type"></textarea>
</div> </div>
<div class="clearfix visible-xs"></div> <div class="clearfix visible-xs"></div>
</div> </div>
</div> </div>
</form> </form>
</li>
</ul>
</div> </div>

View File

@@ -0,0 +1,217 @@
<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.showHAL" role="presentation"><a href="#/HAL">HAL</a></li>
<li ng-if="bridge.showHue" role="presentation"><a
href="#/huedevices">Hue Devices</a></li>
<li role="presentation" class="active"><a href="#/haldevices">HAL
Devices</a></li>
<li role="presentation"><a href="#/editor">Manual Add</a></li>
</ul>
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">HAL Device List
({{bridge.haldevices.length}})</h2>
</div>
<div class="panel-body">
<p class="text-muted">For any HAL 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 HAL Devices' list below will show what
is already setup for your HAL.</p>
<p>
Also, use this select menu for which type of dim control you would
like to be generated: <select name="device-dim-control"
id="device-dim-control" ng-model="device_dim_control">
<option value="">none</option>
<option value="${intensity.byte}">Pass-thru Value</option>
<option value="${intensity.percent}">Percentage</option>
<option value="${intensity.math(X*1)}">Custom Math</option>
</select>
</p>
<p>Use the check boxes by the names to use the bulk addition
feature. Select your items and dim control type if wanted, 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 HAL.</p>
</div>
<scrollable-table watch="bridge.haldevices">
<table class="table table-bordered table-striped table-hover">
<thead>
<tr>
<th>Row</th>
<th sortable-header col="name">
<span><input type="checkbox" name="selectAll"
value="{{selectAll}}"
ng-checked="selectAll"
ng-click="toggleSelectAll()"> Name</span></th>
<th sortable-header col="category">Category</th>
<th sortable-header col="halname">HAL</th>
<th>On Button</th>
<th>Off Button</th>
<th>Actions</th>
</tr>
</thead>
<tr ng-repeat="haldevice in bridge.haldevices | availableHalDeviceId">
<td>{{$index+1}}</td>
<td><input type="checkbox" name="bulk.devices[]"
value="{{haldevice.haldevicename}}"
ng-checked="bulk.devices.indexOf(haldevice.haldevicename) > -1"
ng-click="toggleSelection(haldevice.haldevicename)">
{{haldevice.haldevicename}}</td>
<td>{{haldevice.haldevicetype}}</td>
<td>{{haldevice.halname}}</td>
<td>
<select name="button-on" id="button-on" ng-model="button_on">
<option ng-repeat="aButtonOn in haldevice.buttons.DeviceElements"
value="{{aButtonOn}}">{{aButtonOn.DeviceName}}</option>
</select>
</td>
<td>
<select name="button-off" id="button-off" ng-model="button_off">
<option ng-repeat="aButtonOff in haldevice.buttons.DeviceElements"
value="{{aButtonOff}}">{{aButtonOff.DeviceName}}</option>
</select>
</td>
<td>
<button ng-if="haldevice.haldevicetype != 'Home' && haldevice.haldevicetype != 'HVAC' && haldevice.haldevicetype != 'IrData'" class="btn btn-success" type="submit"
ng-click="buildDeviceUrls(haldevice, device_dim_control)">Generate
Bridge Device</button>
<button ng-if="haldevice.haldevicetype == 'Home'" class="btn btn-success" type="submit"
ng-click="buildHALHomeUrls(haldevice)">Home/Away</button>
<button ng-if="haldevice.haldevicetype == 'IrData'" class="btn btn-success" type="submit"
ng-click="buildButtonUrls(haldevice, button_on, button_off)">Build
A Button</button>
<ul ng-if="haldevice.haldevicetype == 'HVAC'" class="list-group">
<li class="list-group-item">
<p>
<button class="btn btn-success" type="submit"
ng-click="buildHALHeatUrls(haldevice)">Heat</button>
<button class="btn btn-success" type="submit"
ng-click="buildHALCoolUrls(haldevice)">Cool</button>
<button class="btn btn-success" type="submit"
ng-click="buildHALAutoUrls(haldevice)">Auto</button>
</p>
<p>
<button class="btn btn-success" type="submit"
ng-click="buildHALOffUrls(haldevice)">Off</button>
<button class="btn btn-success" type="submit"
ng-click="buildHALFanUrls(haldevice)">Fan</button>
</p>
</li>
</ul>
</td>
</tr>
</table>
</scrollable-table>
<div class="panel-footer">
<button class="btn btn-success" type="submit"
ng-click="bulkAddDevices(device_dim_control)">Bulk Add
({{bulk.devices.length}})</button>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">
Already Configured HAL Devices <a ng-click="toggleButtons()"><span
class={{imgButtonsUrl}} aria-hidden="true"></span></a></a>
</h2>
</div>
<scrollable-table ng-if="buttonsVisible" watch="bridge.haldevices">
<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="category">Category</th>
<th sortable-header col="halname">HAL</th>
<th>Actions</th>
</tr>
</thead>
<tr
ng-repeat="device in bridge.devices | unavailableHalDeviceId">
<td>{{$index+1}}</td>
<td>{{device.name}}</td>
<td>{{device.deviceType}}</td>
<td>{{device.targetDevice}}</td>
<td>
<button class="btn btn-danger" type="submit"
ng-click="deleteDeviceByMapId(device.mapId, device.mapType)">Delete</button>
</td>
</tr>
</table>
</scrollable-table>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">Add Bridge Device for a HAL Device</h2>
</div>
<div class="panel-body">
<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>
<div class="form-group">
<div class="row">
<label class="col-xs-12 col-sm-2 control-label"
for="device-dim-url">Dim URL </label>
<div class="col-xs-8 col-sm-7">
<textarea rows="3" class="form-control" id="device-dim-url"
ng-model="device.dimUrl" placeholder="URL to dim device"></textarea>
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<label class="col-xs-12 col-sm-2 control-label"
for="device-off-url">Off URL </label>
<div class="col-xs-8 col-sm-7">
<textarea rows="3" class="form-control" id="device-off-url"
ng-model="device.offUrl" placeholder="URL to turn device off"></textarea>
</div>
</div>
</form>
</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>

View File

@@ -2,23 +2,34 @@
<li role="presentation"><a href="#">Bridge Devices</a></li> <li role="presentation"><a href="#">Bridge Devices</a></li>
<li role="presentation"><a href="#/system">Bridge Control</a></li> <li role="presentation"><a href="#/system">Bridge Control</a></li>
<li role="presentation"><a href="#/logs">Logs</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
<li ng-if="bridge.showVera" role="presentation"><a href="#/verascenes">Vera Scenes</a></li> href="#/veradevices">Vera Devices</a></li>
<li role="presentation" class="active"><a href="#/harmonyactivities">Harmony Activities</a></li> <li ng-if="bridge.showVera" role="presentation"><a
<li role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li> href="#/verascenes">Vera Scenes</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 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 ng-if="bridge.showHal" role="presentation"><a
href="#/haldevices">HAL 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">
<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>
<ul class="list-group"> <div class="panel-body">
<li class="list-group-item"> <p class="text-muted">For any Harmony Activity, use the action
<p class="text-muted">For any Harmony Activity, use the action buttons to generate the device addition information below automatically. buttons to generate the device addition information below
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. automatically. Then you can modify the name to anything you want that
The 'Already Configured Activities' list below will show what is already setup for your Harmony Hubs.</p> will be the keyword for Alexa. Click the 'Add Bridge Device' to
finish that selection setup. The 'Already Configured Activities' list
below will show what is already setup for your Harmony Hubs.</p>
</div>
<scrollable-table watch="bridge.harmonyactivities"> <scrollable-table watch="bridge.harmonyactivities">
<table class="table table-bordered table-striped table-hover"> <table class="table table-bordered table-striped table-hover">
@@ -31,7 +42,8 @@
<th>Actions</th> <th>Actions</th>
</tr> </tr>
</thead> </thead>
<tr ng-repeat="harmonyactivity in bridge.harmonyactivities | availableHarmonyActivityId"> <tr
ng-repeat="harmonyactivity in bridge.harmonyactivities | availableHarmonyActivityId">
<td>{{$index+1}}</td> <td>{{$index+1}}</td>
<td>{{harmonyactivity.activity.label}}</td> <td>{{harmonyactivity.activity.label}}</td>
<td>{{harmonyactivity.activity.id}}</td> <td>{{harmonyactivity.activity.id}}</td>
@@ -39,19 +51,21 @@
<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
Activity URLs</button> Bridge Device</button>
</td> </td>
</tr> </tr>
</table> </table>
</scrollable-table> </scrollable-table>
</li>
</ul>
<div class="panel-heading">
<h2 class="panel-title">Already Configured Activities <a ng-click="toggleButtons()"><span class={{imgButtonsUrl}} aria-hidden="true"></span></a></h2>
</div> </div>
<ul ng-if="buttonsVisible" class="list-group"> <div class="panel panel-default">
<li class="list-group-item"> <div class="panel-heading">
<scrollable-table watch="bridge.harmonyactivities"> <h2 class="panel-title">
Already Configured Activities <a ng-click="toggleButtons()"><span
class={{imgButtonsUrl}} aria-hidden="true"></span></a>
</h2>
</div>
<scrollable-table ng-if="buttonsVisible"
watch="bridge.harmonyactivities">
<table class="table table-bordered table-striped table-hover"> <table class="table table-bordered table-striped table-hover">
<thead> <thead>
<tr> <tr>
@@ -62,7 +76,8 @@
<th>Actions</th> <th>Actions</th>
</tr> </tr>
</thead> </thead>
<tr ng-repeat="harmonyactivity in bridge.harmonyactivities | unavailableHarmonyActivityId"> <tr
ng-repeat="harmonyactivity in bridge.harmonyactivities | unavailableHarmonyActivityId">
<td>{{$index+1}}</td> <td>{{$index+1}}</td>
<td>{{harmonyactivity.activity.label}}</td> <td>{{harmonyactivity.activity.label}}</td>
<td>{{harmonyactivity.activity.id}}</td> <td>{{harmonyactivity.activity.id}}</td>
@@ -72,15 +87,13 @@
</tr> </tr>
</table> </table>
</scrollable-table> </scrollable-table>
</li>
</ul>
</div> </div>
<div class="panel panel-default bridgeServer" ng-if="!bridge.error"> <div class="panel panel-default">
<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>
<ul class="list-group"> <div class="panel-body">
<li class="list-group-item">
<form class="form-horizontal"> <form class="form-horizontal">
<div class="form-group"> <div class="form-group">
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name <label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
@@ -90,8 +103,8 @@
<input type="text" class="form-control" id="device-name" <input type="text" class="form-control" id="device-name"
ng-model="device.name" placeholder="Device Name"> ng-model="device.name" placeholder="Device Name">
</div> </div>
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary" ng-click="addDevice()"> <button type="submit" class="col-xs-4 col-sm-2 btn btn-primary"
Add Bridge Device</button> ng-click="addDevice()">Add Bridge Device</button>
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="row"> <div class="row">
@@ -118,6 +131,15 @@
</div> </div>
</div> </div>
</form> </form>
</li>
</ul>
</div> </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>

View File

@@ -2,24 +2,37 @@
<li role="presentation"><a href="#">Bridge Devices</a></li> <li role="presentation"><a href="#">Bridge Devices</a></li>
<li role="presentation"><a href="#/system">Bridge Control</a></li> <li role="presentation"><a href="#/system">Bridge Control</a></li>
<li role="presentation"><a href="#/logs">Logs</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
<li ng-if="bridge.showVera" role="presentation"><a href="#/verascenes">Vera Scenes</a></li> href="#/veradevices">Vera Devices</a></li>
<li role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li> <li ng-if="bridge.showVera" role="presentation"><a
<li role="presentation" class="active"><a href="#/harmonydevices">Harmony Devices</a></li> href="#/verascenes">Vera Scenes</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 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 ng-if="bridge.showHal" role="presentation"><a
href="#/haldevices">HAL 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">
<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>
<ul class="list-group"> <div class="panel-body">
<li class="list-group-item"> <p class="text-muted">For any Harmony Device and Buttons, use the
<p class="text-muted">For any Harmony Device and Buttons, use the build button to generate the configuration for this bridge device. You can add button presses by build button to generate the configuration for this bridge device.
selecting yoru devic and buttons and then selecting the Build Button. This will allow multiple button presses to be built for a given device. You can add button presses by selecting yoru devic and buttons and
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. then selecting the Build Button. This will allow multiple button
The 'Already Configured Harmony Buttons' list below will show what is already setup for your Harmony Hubs.</p> presses to be built for a given device. 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 Harmony Buttons' list below will show what is already
setup for your Harmony Hubs.</p>
</div>
<scrollable-table watch="bridge.harmonydevices"> <scrollable-table watch="bridge.harmonydevices">
<table class="table table-bordered table-striped table-hover"> <table class="table table-bordered table-striped table-hover">
@@ -39,35 +52,41 @@
<td>{{harmonydevice.device.label}}</td> <td>{{harmonydevice.device.label}}</td>
<td>{{harmonydevice.device.id}}</td> <td>{{harmonydevice.device.id}}</td>
<td>{{harmonydevice.hub}}</td> <td>{{harmonydevice.hub}}</td>
<td> <td><select name="device-ctrlon" id="device-ctrlon"
<select name="device-ctrlon" id="device-ctrlon" ng-model="devicectrlon"> ng-model="devicectrlon">
<optgroup ng-repeat="ctrlon in harmonydevice.device.controlGroup" label="{{ctrlon.name}}"> <optgroup ng-repeat="ctrlon in harmonydevice.device.controlGroup"
<option ng-repeat="funcon in ctrlon.function" value="{{funcon.action}}">{{funcon.label}}</option> label="{{ctrlon.name}}">
<option ng-repeat="funcon in ctrlon.function"
value="{{funcon.action}}">{{funcon.label}}</option>
</optgroup> </optgroup>
</select> </select></td>
</td> <td><select name="device-ctrloff" id="device-ctrloff"
<td> ng-model="devicectrloff">
<select name="device-ctrloff" id="device-ctrloff" ng-model="devicectrloff"> <optgroup ng-repeat="ctrloff in harmonydevice.device.controlGroup"
<optgroup ng-repeat="ctrloff in harmonydevice.device.controlGroup" label="{{ctrloff.name}}"> label="{{ctrloff.name}}">
<option ng-repeat="funcoff in ctrloff.function" value="{{funcoff.action}}">{{funcoff.label}}</option> <option ng-repeat="funcoff in ctrloff.function"
value="{{funcoff.action}}">{{funcoff.label}}</option>
</optgroup> </optgroup>
</select> </select></td>
</td>
<td> <td>
<button class="btn btn-success" type="submit" <button class="btn btn-success" type="submit"
ng-click="buildButtonUrls(harmonydevice, devicectrlon, devicectrloff)">Build A Button</button> ng-click="buildButtonUrls(harmonydevice, devicectrlon, devicectrloff)">Build
A Button</button>
</td> </td>
</tr> </tr>
</table> </table>
</scrollable-table> </scrollable-table>
</li> </li>
</ul> </ul>
<div class="panel-heading">
<h2 class="panel-title">Already Configured Harmony Buttons <a ng-click="toggleButtons()"><span class={{imgButtonsUrl}} aria-hidden="true"></span></a></h2>
</div> </div>
<ul ng-if="buttonsVisible" class="list-group"> <div class="panel panel-default">
<li class="list-group-item"> <div class="panel-heading">
<scrollable-table watch="bridge.harmonydevices"> <h2 class="panel-title">
Already Configured Harmony Buttons <a ng-click="toggleButtons()"><span
class={{imgButtonsUrl}} aria-hidden="true"></span></a>
</h2>
</div>
<scrollable-table ng-if="buttonsVisible" watch="bridge.harmonydevices">
<table class="table table-bordered table-striped table-hover"> <table class="table table-bordered table-striped table-hover">
<thead> <thead>
<tr> <tr>
@@ -79,7 +98,8 @@
<th>Actions</th> <th>Actions</th>
</tr> </tr>
</thead> </thead>
<tr ng-repeat="device in bridge.devices | configuredButtons | orderBy:predicate:reverse"> <tr
ng-repeat="device in bridge.devices | configuredButtons | orderBy:predicate:reverse">
<td>{{$index+1}}</td> <td>{{$index+1}}</td>
<td>{{device.name}}</td> <td>{{device.name}}</td>
<td>{{device.id}}</td> <td>{{device.id}}</td>
@@ -92,15 +112,12 @@
</tr> </tr>
</table> </table>
</scrollable-table> </scrollable-table>
</li>
</ul>
</div> </div>
<div class="panel panel-default bridgeServer" ng-if="!bridge.error"> <div class="panel panel-default">
<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>
<ul class="list-group"> <div class="panel-body">
<li class="list-group-item">
<form class="form-horizontal"> <form class="form-horizontal">
<div class="form-group"> <div class="form-group">
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name <label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
@@ -110,8 +127,8 @@
<input type="text" class="form-control" id="device-name" <input type="text" class="form-control" id="device-name"
ng-model="device.name" placeholder="Device Name"> ng-model="device.name" placeholder="Device Name">
</div> </div>
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary" ng-click="addDevice()"> <button type="submit" class="col-xs-4 col-sm-2 btn btn-primary"
Add Bridge Device</button> ng-click="addDevice()">Add Bridge Device</button>
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="row"> <div class="row">
@@ -138,6 +155,15 @@
</div> </div>
</div> </div>
</form> </form>
</li>
</ul>
</div> </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>

View File

@@ -0,0 +1,148 @@
<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 ng-if="bridge.showHal" role="presentation"><a
href="#/haldevices">HAL Devices</a></li>
<li role="presentation"><a href="#/editor">Manual Add</a></li>
</ul>
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">Hue Device List
({{bridge.huedevices.length}})</h2>
</div>
<div class="panel-body">
<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>
</div>
<scrollable-table watch="bridge.huedevices">
<table class="table table-bordered table-striped table-hover">
<thead>
<tr>
<th>Row</th>
<th sortable-header col="name"><span><input type="checkbox" name="selectAll"
value="{{selectAll}}"
ng-checked="selectAll"
ng-click="toggleSelectAll()"> Name</span></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>
<div class="panel-footer">
<button class="btn btn-success" type="submit"
ng-click="bulkAddDevices()">Bulk Add
({{bulk.devices.length}})</button>
</div>
</div>
<div class="panel panel-default">
<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>
<scrollable-table ng-if="buttonsVisible" 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>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">Add Bridge Device for a Hue Device</h2>
</div>
<div class="panel-body">
<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>
</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>

View File

@@ -2,23 +2,32 @@
<li role="presentation"><a href="#">Bridge Devices</a></li> <li role="presentation"><a href="#">Bridge Devices</a></li>
<li role="presentation"><a href="#/system">Bridge Control</a></li> <li role="presentation"><a href="#/system">Bridge Control</a></li>
<li role="presentation" class="active"><a href="#/logs">Logs</a></li> <li role="presentation" class="active"><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
<li ng-if="bridge.showVera" role="presentation"><a href="#/verascenes">Vera Scenes</a></li> href="#/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li> <li ng-if="bridge.showVera" role="presentation"><a
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li> 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 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 ng-if="bridge.showHal" role="presentation"><a
href="#/haldevices">HAL 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"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<h1 class="panel-title">Log Messages</h1> <h1 class="panel-title">Log Messages</h1>
</div> </div>
<div class="panel-body"> <div class="panel-body">
<p> <p>
<button class="btn btn-primary" type="submit" <button class="btn btn-primary" type="submit" ng-click="updateLogs()">Update
ng-click="updateLogs()">Update Log</button> Log</button>
</p> </p>
</div>
<scrollable-table watch="bridge.logMsgs"> <scrollable-table watch="bridge.logMsgs">
<table class="table table-striped table-bordered table-hover"> <table class="table table-striped table-bordered table-hover">
<thead> <thead>
@@ -38,17 +47,20 @@
</table> </table>
</scrollable-table> </scrollable-table>
</div> </div>
</div> <div class="panel panel-default">
<div class="panel panel-default logconfig">
<div class="panel-heading"> <div class="panel-heading">
<h1 class="panel-title">Logging Configuration <a ng-click="toggle()"><span class={{imgUrl}} aria-hidden="true"></a></h1> <h1 class="panel-title">
Logging Configuration <a ng-click="toggle()"><span
class={{imgUrl}} aria-hidden="true"></a>
</h1>
</div> </div>
<div ng-if="visible" class="animate-if" class="panel-body"> <div ng-if="visible" class="animate-if" class="panel-body">
<p> <p>
<button class="btn btn-primary" type="submit" <button class="btn btn-primary" type="submit"
ng-click="updateLoggers()">Update Log Levels</button> ng-click="updateLoggers()">Update Log Levels</button>
Show All Loggers <input type="checkbox" ng-model="bridge.logShowAll" Show All Loggers <input type="checkbox" ng-model="bridge.logShowAll"
ng-change="reloadLoggers()" ng-true-value=true ng-false-value=false> {{bridge.logShowAll}} ng-change="reloadLoggers()" ng-true-value=true ng-false-value=false>
{{bridge.logShowAll}}
</p> </p>
<scrollable-table watch="bridge.loggerInfo"> <scrollable-table watch="bridge.loggerInfo">
<table class="table table-bordered table-striped table-hover"> <table class="table table-bordered table-striped table-hover">
@@ -62,14 +74,12 @@
<tr ng-repeat="logInfo in bridge.loggerInfo"> <tr ng-repeat="logInfo in bridge.loggerInfo">
<td>{{logInfo.logLevel.substr(0,logInfo.logLevel.indexOf("_"))}}</td> <td>{{logInfo.logLevel.substr(0,logInfo.logLevel.indexOf("_"))}}</td>
<td>{{logInfo.loggerName}}</td> <td>{{logInfo.loggerName}}</td>
<td> <td><select name="new-log-level" id="new-log-level"
<select name="new-log-level" id="new-log-level" ng-change="addToUpdate(logInfo)" ng-model="logInfo.newLogLevel"> ng-change="addToUpdate(logInfo)" ng-model="logInfo.newLogLevel">
<option ng-repeat="alevel in levels" value="{{alevel}}">{{alevel.substr(0,alevel.indexOf("_"))}}</option> <option ng-repeat="alevel in levels" value="{{alevel}}">{{alevel.substr(0,alevel.indexOf("_"))}}</option>
</select> </select></td>
</td>
</tr> </tr>
</table> </table>
</scrollable-table> </scrollable-table>
</div> </div>
</div> </div>

View File

@@ -2,23 +2,34 @@
<li role="presentation"><a href="#">Bridge Devices</a></li> <li role="presentation"><a href="#">Bridge Devices</a></li>
<li role="presentation"><a href="#/system">Bridge Control</a></li> <li role="presentation"><a href="#/system">Bridge Control</a></li>
<li role="presentation"><a href="#/logs">Logs</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
<li ng-if="bridge.showVera" role="presentation"><a href="#/verascenes">Vera Scenes</a></li> href="#/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li> <li ng-if="bridge.showVera" role="presentation"><a
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li> 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 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 ng-if="bridge.showHal" role="presentation"><a
href="#/haldevices">HAL 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">
<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>
<ul class="list-group"> <div class="panel-body">
<li class="list-group-item"> <p class="text-muted">For any Nest Item, use the action buttons to
<p class="text-muted">For any Nest Item, use the action buttons to generate the device addition information below automatically. generate the device addition information below automatically. Then
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. you can modify the name to anything you want that will be the keyword
The 'Already Configured Nest Items' list below will show what is already setup for your Nest.</p> for Alexa. Click the 'Add Bridge Device' to finish that selection
setup. The 'Already Configured Nest Items' list below will show what
is already setup for your Nest.</p>
</div>
<scrollable-table watch="bridge.nestitems"> <scrollable-table watch="bridge.nestitems">
<table class="table table-bordered table-striped table-hover"> <table class="table table-bordered table-striped table-hover">
@@ -31,7 +42,8 @@
<th>Actions</th> <th>Actions</th>
</tr> </tr>
</thead> </thead>
<tr ng-repeat="nestitem in bridge.nestitems | availableNestItemId | orderBy:predicate:reverse"> <tr
ng-repeat="nestitem in bridge.nestitems | availableNestItemId | orderBy:predicate:reverse">
<td>{{$index+1}}</td> <td>{{$index+1}}</td>
<td>{{nestitem.name}}</td> <td>{{nestitem.name}}</td>
<td>{{nestitem.type}}</td> <td>{{nestitem.type}}</td>
@@ -65,14 +77,15 @@
</tr> </tr>
</table> </table>
</scrollable-table> </scrollable-table>
</li>
</ul>
<div class="panel-heading">
<h2 class="panel-title">Already Configured Nest Items <a ng-click="toggleButtons()"><span class={{imgButtonsUrl}} aria-hidden="true"></span></a></h2>
</div> </div>
<ul ng-if="buttonsVisible" class="list-group"> <div class="panel panel-default">
<li class="list-group-item"> <div class="panel-heading">
<scrollable-table watch="bridge.nestitems"> <h2 class="panel-title">
Already Configured Nest Items <a ng-click="toggleButtons()"><span
class={{imgButtonsUrl}} aria-hidden="true"></span></a>
</h2>
</div>
<scrollable-table ng-if="buttonsVisible" watch="bridge.nestitems">
<table class="table table-bordered table-striped table-hover"> <table class="table table-bordered table-striped table-hover">
<thead> <thead>
<tr> <tr>
@@ -83,7 +96,8 @@
<th>Actions</th> <th>Actions</th>
</tr> </tr>
</thead> </thead>
<tr ng-repeat="device in bridge.devices | unavailableNestItemId | orderBy:predicate:reverse"> <tr
ng-repeat="device in bridge.devices | unavailableNestItemId | orderBy:predicate:reverse">
<td>{{$index+1}}</td> <td>{{$index+1}}</td>
<td>{{device.name}}</td> <td>{{device.name}}</td>
<td>{{device.id}}</td> <td>{{device.id}}</td>
@@ -93,15 +107,12 @@
</tr> </tr>
</table> </table>
</scrollable-table> </scrollable-table>
</li>
</ul>
</div> </div>
<div class="panel panel-default bridgeServer" ng-if="!bridge.error"> <div class="panel panel-default">
<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>
<ul class="list-group"> <div class="panel-body">
<li class="list-group-item">
<form class="form-horizontal"> <form class="form-horizontal">
<div class="form-group"> <div class="form-group">
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name <label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
@@ -111,8 +122,8 @@
<input type="text" class="form-control" id="device-name" <input type="text" class="form-control" id="device-name"
ng-model="device.name" placeholder="Device Name"> ng-model="device.name" placeholder="Device Name">
</div> </div>
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary" ng-click="addDevice()"> <button type="submit" class="col-xs-4 col-sm-2 btn btn-primary"
Add Bridge Device</button> ng-click="addDevice()">Add Bridge Device</button>
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="row"> <div class="row">
@@ -139,6 +150,15 @@
</div> </div>
</div> </div>
</form> </form>
</li>
</ul>
</div> </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>

View File

@@ -1,16 +1,25 @@
<ul class="nav nav-pills" role="tablist"> <ul class="nav nav-pills" role="tablist">
<li role="presentation"><a href="#">Bridge Devices</a></li> <li role="presentation"><a href="#">Bridge Devices</a></li>
<li role="presentation" class="active"><a href="#/system">Bridge Control</a></li> <li role="presentation" class="active"><a href="#/system">Bridge
Control</a></li>
<li role="presentation"><a href="#/logs">Logs</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
<li ng-if="bridge.showVera" role="presentation"><a href="#/verascenes">Vera Scenes</a></li> href="#/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li> <li ng-if="bridge.showVera" role="presentation"><a
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li> 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 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 ng-if="bridge.showHal" role="presentation"><a
href="#/haldevices">HAL 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"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<h1 class="panel-title">Bridge Settings</h1> <h1 class="panel-title">Bridge Settings</h1>
</div> </div>
@@ -26,21 +35,19 @@
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">
<p> <p>
<button ng-disabled="form.$pristine || bridge.isInControl" class="btn btn-success" type="submit" <button ng-disabled="bridge.isInControl"
ng-click="saveSettings()">Save</button> class="btn btn-success" type="submit" ng-click="saveSettings()">Save</button>
<button ng-disabled="bridge.isInControl" class="btn btn-warning" type="submit" <button ng-disabled="bridge.isInControl" class="btn btn-warning"
ng-click="bridgeReinit()">Bridge Reinitialize</button> type="submit" ng-click="bridgeReinit()">Bridge
<button ng-disabled="bridge.isInControl" class="btn btn-danger" type="submit" Reinitialize</button>
ng-click="bridgeStop()">Bridge Stop</button> <button ng-disabled="bridge.isInControl" class="btn btn-danger"
<button class="btn btn-primary" type="submit" type="submit" ng-click="bridgeStop()">Bridge Stop</button>
onclick="myRefresh()">Refresh</button> <button class="btn btn-primary" type="submit" onclick="myRefresh()">Refresh</button>
<script> <script>
function myRefresh() { function myRefresh() {
location.reload(); location.reload();
@@ -56,32 +63,41 @@
</thead> </thead>
<tr> <tr>
<td>Configuration Path and File</td> <td>Configuration Path and File</td>
<td><input id="bridge-settings-configfile" class="form-control" type="text" <td><input id="bridge-settings-configfile"
ng-model="bridge.settings.configfile" placeholder="data/ha-bridge.config"></td> class="form-control" type="text"
ng-model="bridge.settings.configfile"
placeholder="data/ha-bridge.config"></td>
</tr> </tr>
<tr> <tr>
<td>Device DB Path and File</td> <td>Device DB Path and File</td>
<td><input id="bridge-settings-upnpdevicedb" class="form-control" type="text" <td><input id="bridge-settings-upnpdevicedb"
ng-model="bridge.settings.upnpdevicedb" placeholder="data/device.db"></td> class="form-control" type="text"
ng-model="bridge.settings.upnpdevicedb"
placeholder="data/device.db"></td>
</tr> </tr>
<tr> <tr>
<td>UPNP IP Address</td> <td>UPNP IP Address</td>
<td><input id="bridge-settings-upnpconfigaddress" class="form-control" type="text" <td><input id="bridge-settings-upnpconfigaddress"
ng-model="bridge.settings.upnpconfigaddress" placeholder="192.168.1.1"></td> class="form-control" type="text"
ng-model="bridge.settings.upnpconfigaddress"
placeholder="192.168.1.1"></td>
</tr> </tr>
<tr> <tr>
<td>Web Server Port</td> <td>Web Server Port</td>
<td><input id="bridge-settings-serverport" class="form-control" type="number" <td><input id="bridge-settings-serverport"
class="form-control" type="number"
ng-model="bridge.settings.serverport" min="1" max="65535"></td> ng-model="bridge.settings.serverport" min="1" max="65535"></td>
</tr> </tr>
<tr> <tr>
<td>UPNP Response Port</td> <td>UPNP Response Port</td>
<td><input id="bridge-settings-upnpresponseport" class="form-control" type="number" <td><input id="bridge-settings-upnpresponseport"
class="form-control" type="number"
ng-model="bridge.settings.upnpresponseport" min="1" max="65535"></td> ng-model="bridge.settings.upnpresponseport" min="1" max="65535"></td>
</tr> </tr>
<tr> <tr>
<td>Vera Names and IP Addresses</td> <td>Vera Names and IP Addresses</td>
<td><table class="table table-bordered table-striped table-hover"> <td><table
class="table table-bordered table-striped table-hover">
<thead> <thead>
<tr> <tr>
<th>Name</th> <th>Name</th>
@@ -96,19 +112,21 @@
ng-click="removeVeratoSettings(vera.name, vera.ip)">Del</button></td> ng-click="removeVeratoSettings(vera.name, vera.ip)">Del</button></td>
</tr> </tr>
<tr> <tr>
<td><input id="bridge-settings-next-vera-name" class="form-control" type="text" <td><input id="bridge-settings-next-vera-name"
ng-model="newveraname" placeholder="A Vera"></td> class="form-control" type="text" ng-model="newveraname"
<td><input id="bridge-settings-next-vera-ip" class="form-control" type="text" placeholder="A Vera"></td>
ng-model="newveraip" placeholder="192.168.1.2"></td> <td><input id="bridge-settings-next-vera-ip"
class="form-control" type="text" ng-model="newveraip"
placeholder="192.168.1.2"></td>
<td><button class="btn btn-success" type="submit" <td><button class="btn btn-success" type="submit"
ng-click="addVeratoSettings(newveraname, newveraip)">Add</button></td> ng-click="addVeratoSettings(newveraname, newveraip)">Add</button></td>
</tr> </tr>
</table> </table></td>
</td>
</tr> </tr>
<tr> <tr>
<td>Harmony Names and IP Addresses</td> <td>Harmony Names and IP Addresses</td>
<td><table class="table table-bordered table-striped table-hover"> <td><table
class="table table-bordered table-striped table-hover">
<thead> <thead>
<tr> <tr>
<th>Name</th> <th>Name</th>
@@ -123,80 +141,162 @@
ng-click="removeHarmonytoSettings(harmony.name, harmony.ip)">Del</button></td> ng-click="removeHarmonytoSettings(harmony.name, harmony.ip)">Del</button></td>
</tr> </tr>
<tr> <tr>
<td><input id="bridge-settings-next-harmony-name" class="form-control" type="text" <td><input id="bridge-settings-next-harmony-name"
ng-model="newharmonyname" placeholder="A Harmony"></td> class="form-control" type="text" ng-model="newharmonyname"
<td><input id="bridge-settings-next-harmony-ip" class="form-control" type="text" placeholder="A Harmony"></td>
ng-model="newharmonyip" placeholder="192.168.1.3"></td> <td><input id="bridge-settings-next-harmony-ip"
class="form-control" type="text" ng-model="newharmonyip"
placeholder="192.168.1.3"></td>
<td><button class="btn btn-success" type="submit" <td><button class="btn btn-success" type="submit"
ng-click="addHarmonytoSettings(newharmonyname, newharmonyip)">Add</button></td> ng-click="addHarmonytoSettings(newharmonyname, newharmonyip)">Add</button></td>
</tr> </tr>
</table> </table></td>
</td>
</tr> </tr>
<tr> <tr>
<td>Harmony Username</td> <td>Harmony Username</td>
<td><input id="bridge-settings-harmonyuser" class="form-control" type="text" <td><input id="bridge-settings-harmonyuser"
ng-model="bridge.settings.harmonyuser" placeholder="someone@gmail.com"></td> class="form-control" type="text"
ng-model="bridge.settings.harmonyuser"
placeholder="someone@gmail.com"></td>
</tr> </tr>
<tr> <tr>
<td>Harmony Password</td> <td>Harmony Password</td>
<td><input id="bridge-settings-harmonypwd" class="form-control" type="password" <td><input id="bridge-settings-harmonypwd"
class="form-control" type="password"
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
ng-model="bridge.settings.buttonsleep" min="100" max="9999"></td> class="table table-bordered table-striped table-hover">
<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>
<td>HAL Names and IP Addresses</td>
<td><table
class="table table-bordered table-striped table-hover">
<thead>
<tr>
<th>Name</th>
<th>IP</th>
<th>Manage</th>
</tr>
</thead>
<tr ng-repeat="hal in bridge.settings.haladdress.devices">
<td>{{hal.name}}</td>
<td>{{hal.ip}}</td>
<td><button class="btn btn-danger" type="submit"
ng-click="removeHaltoSettings(hal.name, hal.ip)">Del</button></td>
</tr>
<tr>
<td><input id="bridge-settings-next-hal-name"
class="form-control" type="text" ng-model="newhalname"
placeholder="A Hal"></td>
<td><input id="bridge-settings-next-hal-ip"
class="form-control" type="text" ng-model="newhalip"
placeholder="192.168.1.3:82"></td>
<td><button class="btn btn-success" type="submit"
ng-click="addHaltoSettings(newhalname, newhalip)">Add</button></td>
</tr>
</table></td>
</tr>
<tr>
<td>HAL Token</td>
<td><input id="bridge-settings-haltoken" class="form-control"
type="password" ng-model="bridge.settings.haltoken"
placeholder="thetoken"></td>
</tr> </tr>
<tr> <tr>
<td>Nest Username</td> <td>Nest Username</td>
<td><input id="bridge-settings-nestuser" class="form-control" type="text" <td><input id="bridge-settings-nestuser" class="form-control"
ng-model="bridge.settings.nestuser" placeholder="someone@gmail.com"></td> type="text" ng-model="bridge.settings.nestuser"
placeholder="someone@gmail.com"></td>
</tr> </tr>
<tr> <tr>
<td>Nest Password</td> <td>Nest Password</td>
<td><input id="bridge-settings-nestpwd" class="form-control" type="password" <td><input id="bridge-settings-nestpwd" class="form-control"
ng-model="bridge.settings.nestpwd" placeholder="thepassword"></td> type="password" ng-model="bridge.settings.nestpwd"
</tr> placeholder="thepassword"></td>
<tr>
<td>Log Messages to Buffer</td>
<td><input id="bridge-settings-numberoflogmessages" class="form-control" type="number"
ng-model="bridge.settings.numberoflogmessages" min="100" max="65535"></td>
</tr>
<tr>
<td>UPNP Strict Handling</td>
<td><input type="checkbox" ng-model="bridge.settings.upnpstrict"
ng-true-value=true ng-false-value=false> {{bridge.settings.upnpstrict}}</td>
</tr>
<tr>
<td>Trace UPNP Calls</td>
<td><input type="checkbox" ng-model="bridge.settings.traceupnp"
ng-true-value=true ng-false-value=false> {{bridge.settings.traceupnp}}</td>
</tr> </tr>
<tr> <tr>
<td>Nest Temp Farenheit</td> <td>Nest Temp Farenheit</td>
<td><input type="checkbox" ng-model="bridge.settings.farenheit" <td><input type="checkbox"
ng-true-value=true ng-false-value=false> {{bridge.settings.farenheit}}</td> 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>
<td>Log Messages to Buffer</td>
<td><input id="bridge-settings-numberoflogmessages"
class="form-control" type="number"
ng-model="bridge.settings.numberoflogmessages" min="100"
max="65535"></td>
</tr>
<tr>
<td>UPNP Strict Handling</td>
<td><input type="checkbox"
ng-model="bridge.settings.upnpstrict" ng-true-value=true
ng-false-value=false> {{bridge.settings.upnpstrict}}</td>
</tr>
<tr>
<td>Trace UPNP Calls</td>
<td><input type="checkbox"
ng-model="bridge.settings.traceupnp" ng-true-value=true
ng-false-value=false> {{bridge.settings.traceupnp}}</td>
</tr> </tr>
</table> </table>
</form> </form>
</div> </div>
</div> </div>
<div class="panel panel-default backup"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<h1 class="panel-title">Bridge Settings Backup <a ng-click="toggle()"><span class={{imgUrl}} aria-hidden="true"></a></h1> <h1 class="panel-title">
Bridge Settings Backup <a ng-click="toggle()"><span
class={{imgUrl}} aria-hidden="true"></a>
</h1>
</div> </div>
<div ng-if="visible" class="animate-if" class="panel-body"> <div ng-if="visible" class="animate-if" class="panel-body">
<p>Control your backups from this area. Use the default name by hitting backup or specify your own.</p>
<form class="form-horizontal"> <form class="form-horizontal">
<div class="form-group"> <div class="form-group">
<label class="col-xs-12 col-sm-2 control-label" for="backup-name">Backup Settings File Name</label> <label class="col-xs-12 col-sm-2 control-label" for="backup-name">Backup
Settings File Name</label>
<div class="col-xs-8 col-sm-7"> <div class="col-xs-8 col-sm-7">
<input id="backup-name" class="form-control" type="text" <input id="backup-name" class="form-control" type="text"
ng-model="optionalbackupname" placeholder="Optional"> ng-model="optionalbackupname" placeholder="Optional">
</div> </div>
<button type="submit" class="btn btn-primary" <button type="submit" class="btn btn-primary"
ng-click="backupSettings(optionalbackupname)">Backup Settings</button> ng-click="backupSettings(optionalbackupname)">Backup
Settings</button>
</div> </div>
</form> </form>
<table class="table table-bordered table-striped table-hover"> <table class="table table-bordered table-striped table-hover">
@@ -218,4 +318,3 @@
</table> </table>
</div> </div>
</div> </div>

View File

@@ -2,41 +2,57 @@
<li role="presentation"><a href="#">Bridge Devices</a></li> <li role="presentation"><a href="#">Bridge Devices</a></li>
<li role="presentation"><a href="#/system">Bridge Control</a></li> <li role="presentation"><a href="#/system">Bridge Control</a></li>
<li role="presentation"><a href="#/logs">Logs</a></li> <li role="presentation"><a href="#/logs">Logs</a></li>
<li role="presentation" class="active"><a href="#/veradevices">Vera Devices</a></li> <li role="presentation" class="active"><a href="#/veradevices">Vera
Devices</a></li>
<li role="presentation"><a href="#/verascenes">Vera Scenes</a></li> <li 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
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonydevices">Harmony Devices</a></li> 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 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 ng-if="bridge.showHal" role="presentation"><a
href="#/haldevices">HAL 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">
<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>
<ul class="list-group"> <div class="panel-body">
<li class="list-group-item"> <p class="text-muted">For any Vera Device, use the action buttons
<p class="text-muted">For any Vera Device, use the action buttons to generate the device addition information below automatically. to generate the device addition information below automatically. Then
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. you can modify the name to anything you want that will be the keyword
The 'Already Configured Vera Devices' list below will show what is already setup for your Vera.</p> for Alexa. Click the 'Add Bridge Device' to finish that selection
<p>Also, use this select menu for which type of dim setup. The 'Already Configured Vera Devices' list below will show
control you would like to be generated: what is already setup for your Vera.</p>
<select name="device-dim-control" id="device-dim-control" ng-model="device_dim_control"> <p>
Also, use this select menu for which type of dim control you would
like to be generated: <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>
</p> </p>
<p>Use the check boxes by the names to use the bulk addition feature. Select your items and dim control type if wanted, then click bulk add below. <p>Use the check boxes by the names to use the bulk addition
Your items will be added with on and off or dim and off if selected with the name of the device from the Vera. feature. Select your items and dim control type if wanted, then click
</p> 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 Vera.</p>
</div>
<scrollable-table watch="bridge.veradevices"> <scrollable-table watch="bridge.veradevices">
<table class="table table-bordered table-striped table-hover"> <table class="table table-bordered table-striped table-hover">
<thead> <thead>
<tr> <tr>
<th>Row</th> <th>Row</th>
<th sortable-header col="name">Name</th> <th sortable-header col="name"><span><input type="checkbox" name="selectAll"
value="{{selectAll}}"
ng-checked="selectAll"
ng-click="toggleSelectAll()"> Name</span></th>
<th sortable-header col="id">Id</th> <th sortable-header col="id">Id</th>
<th sortable-header col="category">Category</th> <th sortable-header col="category">Category</th>
<th sortable-header col="room">Room</th> <th sortable-header col="room">Room</th>
@@ -44,9 +60,14 @@
<th>Actions</th> <th>Actions</th>
</tr> </tr>
</thead> </thead>
<tr ng-repeat="veradevice in bridge.veradevices | availableVeraDeviceId"> <tr
ng-repeat="veradevice in bridge.veradevices | availableVeraDeviceId">
<td>{{$index+1}}</td> <td>{{$index+1}}</td>
<td><input type="checkbox" name="bulk.devices[]" value="{{veradevice.id}}" ng-checked="bulk.devices.indexOf(veradevice.id) > -1" ng-click="toggleSelection(veradevice.id)"> {{veradevice.name}}</td> <td><input type="checkbox" name="bulk.devices[]"
value="{{veradevice.id}}"
ng-checked="bulk.devices.indexOf(veradevice.id) > -1"
ng-click="toggleSelection(veradevice.id)">
{{veradevice.name}}</td>
<td>{{veradevice.id}}</td> <td>{{veradevice.id}}</td>
<td>{{veradevice.category}}</td> <td>{{veradevice.category}}</td>
<td>{{veradevice.room}}</td> <td>{{veradevice.room}}</td>
@@ -54,23 +75,25 @@
<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
Device URLs</button> Bridge Device</button>
</td> </td>
</tr> </tr>
</table> </table>
</scrollable-table> </scrollable-table>
<p> <div class="panel-footer">
<button class="btn btn-success" type="submit" <button class="btn btn-success" type="submit"
ng-click="bulkAddDevices(device_dim_control)">Bulk Add ({{bulk.devices.length}})</button> ng-click="bulkAddDevices(device_dim_control)">Bulk Add
</p> ({{bulk.devices.length}})</button>
</li>
</ul>
<div class="panel-heading">
<h2 class="panel-title">Already Configured Vera Devices <a ng-click="toggleButtons()"><span class={{imgButtonsUrl}} aria-hidden="true"></span></a></a></h2>
</div> </div>
<ul ng-if="buttonsVisible" class="list-group"> </div>
<li class="list-group-item"> <div class="panel panel-default">
<scrollable-table watch="bridge.veradevices"> <div class="panel-heading">
<h2 class="panel-title">
Already Configured Vera Devices <a ng-click="toggleButtons()"><span
class={{imgButtonsUrl}} aria-hidden="true"></span></a></a>
</h2>
</div>
<scrollable-table ng-if="buttonsVisible" watch="bridge.veradevices">
<table class="table table-bordered table-striped table-hover"> <table class="table table-bordered table-striped table-hover">
<thead> <thead>
<tr> <tr>
@@ -83,7 +106,8 @@
<th>Actions</th> <th>Actions</th>
</tr> </tr>
</thead> </thead>
<tr ng-repeat="veradevice in bridge.veradevices | unavailableVeraDeviceId"> <tr
ng-repeat="veradevice in bridge.veradevices | unavailableVeraDeviceId">
<td>{{$index+1}}</td> <td>{{$index+1}}</td>
<td>{{veradevice.name}}</td> <td>{{veradevice.name}}</td>
<td>{{veradevice.id}}</td> <td>{{veradevice.id}}</td>
@@ -97,15 +121,12 @@
</tr> </tr>
</table> </table>
</scrollable-table> </scrollable-table>
</li>
</ul>
</div> </div>
<div class="panel panel-default bridgeServer" ng-if="!bridge.error"> <div class="panel panel-default">
<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>
<ul class="list-group"> <div class="panel-body">
<li class="list-group-item">
<form class="form-horizontal"> <form class="form-horizontal">
<div class="form-group"> <div class="form-group">
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name <label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
@@ -115,8 +136,8 @@
<input type="text" class="form-control" id="device-name" <input type="text" class="form-control" id="device-name"
ng-model="device.name" placeholder="Device Name"> ng-model="device.name" placeholder="Device Name">
</div> </div>
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary" ng-click="addDevice()"> <button type="submit" class="col-xs-4 col-sm-2 btn btn-primary"
Add Bridge Device</button> ng-click="addDevice()">Add Bridge Device</button>
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="row"> <div class="row">
@@ -132,8 +153,8 @@
</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-dim-url">Dim <label class="col-xs-12 col-sm-2 control-label"
URL </label> for="device-dim-url">Dim URL </label>
<div class="col-xs-8 col-sm-7"> <div class="col-xs-8 col-sm-7">
<textarea rows="3" class="form-control" id="device-dim-url" <textarea rows="3" class="form-control" id="device-dim-url"
@@ -152,6 +173,15 @@
</div> </div>
</div> </div>
</form> </form>
</li>
</ul>
</div> </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>

View File

@@ -3,22 +3,32 @@
<li role="presentation"><a href="#/system">Bridge Control</a></li> <li role="presentation"><a href="#/system">Bridge Control</a></li>
<li role="presentation"><a href="#/logs">Logs</a></li> <li role="presentation"><a href="#/logs">Logs</a></li>
<li role="presentation"><a href="#/veradevices">Vera Devices</a></li> <li role="presentation"><a href="#/veradevices">Vera Devices</a></li>
<li role="presentation" class="active"><a href="#/verascenes">Vera Scenes</a></li> <li role="presentation" class="active"><a href="#/verascenes">Vera
<li ng-if="bridge.showHarmony" role="presentation"><a href="#/harmonyactivities">Harmony Activities</a></li> Scenes</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="#/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 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 ng-if="bridge.showHal" role="presentation"><a
href="#/haldevices">HAL 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">
<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>
<ul class="list-group"> <div class="panel-body">
<li class="list-group-item"> <p class="text-muted">For any Vera Scene, use the action buttons
<p class="text-muted">For any Vera Scene, use the action buttons to generate the device addition information below automatically. to generate the device addition information below automatically. Then
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. you can modify the name to anything you want that will be the keyword
The 'Already Configured Vera Scenes' list below will show what is already setup for your Vera.</p> for Alexa. Click the 'Add Bridge Device' to finish that selection
setup. The 'Already Configured Vera Scenes' list below will show what
is already setup for your Vera.</p>
</div>
<scrollable-table watch="bridge.verascenes"> <scrollable-table watch="bridge.verascenes">
<table class="table table-bordered table-striped table-hover"> <table class="table table-bordered table-striped table-hover">
@@ -40,20 +50,21 @@
<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
Scene URLs</button> Device</button>
</td> </td>
</tr> </tr>
</table> </table>
</scrollable-table> </scrollable-table>
</li>
</ul>
<div class="panel-heading">
<h2 class="panel-title">Already Configured Vera Scenes <a ng-click="toggleButtons()"><span class={{imgButtonsUrl}} aria-hidden="true"></span></a></h2>
</div> </div>
<ul ng-if="buttonsVisible" class="list-group"> <div class="panel panel-default">
<li class="list-group-item"> <div class="panel-heading">
<scrollable-table watch="bridge.verascenes"> <h2 class="panel-title">
Already Configured Vera Scenes <a ng-click="toggleButtons()"><span
class={{imgButtonsUrl}} aria-hidden="true"></span></a>
</h2>
</div>
<scrollable-table ng-if="buttonsVisible" watch="bridge.verascenes">
<table class="table table-bordered table-striped table-hover"> <table class="table table-bordered table-striped table-hover">
<thead> <thead>
<tr> <tr>
@@ -65,7 +76,8 @@
<th>Actions</th> <th>Actions</th>
</tr> </tr>
</thead> </thead>
<tr ng-repeat="verascene in bridge.verascenes | unavailableVeraSceneId"> <tr
ng-repeat="verascene in bridge.verascenes | unavailableVeraSceneId">
<td>{{$index+1}}</td> <td>{{$index+1}}</td>
<td>{{verascene.name}}</td> <td>{{verascene.name}}</td>
<td>{{verascene.id}}</td> <td>{{verascene.id}}</td>
@@ -78,15 +90,12 @@
</tr> </tr>
</table> </table>
</scrollable-table> </scrollable-table>
</li>
</ul>
</div> </div>
<div class="panel panel-default bridgeServer" ng-if="!bridge.error"> <div class="panel panel-default">
<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>
<ul class="list-group"> <div class="panel-body">
<li class="list-group-item">
<form class="form-horizontal"> <form class="form-horizontal">
<div class="form-group"> <div class="form-group">
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name <label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
@@ -96,8 +105,8 @@
<input type="text" class="form-control" id="device-name" <input type="text" class="form-control" id="device-name"
ng-model="device.name" placeholder="Device Name"> ng-model="device.name" placeholder="Device Name">
</div> </div>
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary" ng-click="addDevice()"> <button type="submit" class="col-xs-4 col-sm-2 btn btn-primary"
Add Bridge Device</button> ng-click="addDevice()">Add Bridge Device</button>
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="row"> <div class="row">
@@ -122,6 +131,15 @@
</div> </div>
</div> </div>
</form> </form>
</li>
</ul>
</div> </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>