Compare commits

..

11 Commits

Author SHA1 Message Date
Admin
5a843f7569 Fixed handling when no harmony hub is given. dev.mode was updated as
well.

This closes #14.
2015-12-03 14:36:23 -06:00
Admin
2a52783bb1 Final release of multiple harmony hubs and fixes for GUI.
This closes #5 and #13
2015-12-02 15:42:09 -06:00
Admin
195f1854ec Remove Current Activity object as it is not needed. 2015-12-02 15:35:35 -06:00
Admin
2e5596a6e4 Pre-release of multiple Harmony Hub Support 2015-12-02 15:34:30 -06:00
Admin
9fc13c6c45 Conitinuation of multiple harmony hub implementation. 2015-12-01 16:40:29 -06:00
Admin
4b4d4e36c7 Update filtering capability. Still errors in html/angular. 2015-11-30 16:43:14 -06:00
Admin
1e7bdc560b Start adding components to handle multiple harmony hubs. 2015-11-24 14:27:21 -06:00
Admin
aff0f8d64c Removed the doling out of hue devices on a get call. 2015-11-23 15:17:17 -06:00
Admin
7a812d6e6b Updated VeraInfo to use default http client. Finished work on doling out
devices in the resource manager. Caveat, this did not work well with the
echo. Next version will roll this back.
2015-11-23 15:14:38 -06:00
Admin
26f2105801 First try at doling out lights when requested. 2015-11-20 16:40:43 -06:00
Admin
feef345a3b Update for start of virtualize multiple respnses 2015-11-19 16:43:30 -06:00
25 changed files with 495 additions and 125 deletions

View File

@@ -1,5 +1,5 @@
# ha-bridge
Emulates Philips Hue api to other home automation gateways such as an Amazon Echo. The Bridge has helpers to build devices for the gateway for the Logitech Harmony Hub, Vera, Vera Lite or Vera Edge. Alternatively the Bridge supports custom calls as well. The Bridge handles basic commands such as "On", "Off" and "brightness" commands of the hue protocol.
Emulates Philips Hue api to other home automation gateways such as an Amazon Echo. The Bridge has helpers to build devices for the gateway for the Logitech Harmony Hub, Vera, Vera Lite or Vera Edge. Alternatively the Bridge supports custom calls as well. The Bridge handles basic commands such as "On", "Off" and "brightness" commands of the hue protocol. You can provide multiple harmony hubs for control.
## Build
To customize and build it yourself, build a new jar with maven:
```
@@ -22,8 +22,8 @@ The server defaults to running on port 8080. If you're already running a server
The default location for the db to contain the devices as they are added is "data/devices.db". If you would like a different filename or directory, specify -Dupnp.devices.db=`<directory>/<filename> or <filename>` if it is the same directory.
### -Dupnp.response.port=`<port>`
The upnp response port that will be used. The default is 50000.
### -Dharmony.address=`<ip address>`
The argument for the Harmony Hub address should be given as the system does not have a way to find the address. Supply -Dharmony.address=X.Y.Z.A on the command line to provide it. If a Harmony Hub is not used, do not set it.
### -Dharmony.address=`<ip address>` | `<{devices:[{name:ahub,ip:x.y.w.z},{name:anotherhub,ip:a.b.c.d}]}>`
The argument for the Harmony Hub address should be given as the system does not have a way to find the address. Supply -Dharmony.address=X.Y.Z.A on the command line to provide it. If a Harmony Hub is not used, do not set it. To provide multiple harmony hubs, use the json style notation outlined above to provide the list. This argument is backwards compatible.
### -Dharmony.user=`<username>`
The user name of the MyHarmony.com account for the Harmony Hub. This needs to be given if you are using the Harmony Hub Features, provide -Dharmony.user=`<username>` on the command line.
### -Dharmony.pwd=`<password>`

View File

@@ -5,7 +5,7 @@
<groupId>com.bwssystems.HABridge</groupId>
<artifactId>ha-bridge</artifactId>
<version>1.1.0</version>
<version>1.2.1</version>
<packaging>jar</packaging>
<name>HA Bridge</name>
@@ -33,7 +33,7 @@
<dependency>
<groupId>com.sparkjava</groupId>
<artifactId>spark-core</artifactId>
<version>2.2</version>
<version>2.3</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>

View File

@@ -1,14 +1,17 @@
package com.bwssystems.HABridge;
import java.util.List;
public class BridgeSettings {
private String upnpconfigaddress;
private String serverport;
private String upnpresponseport;
private String upnpdevicedb;
private String veraaddress;
private String harmonyaddress;
private IpList harmonyaddress;
private String harmonyuser;
private String harmonypwd;
private Integer upnpresponsedevices;
private boolean upnpstrict;
private boolean traceupnp;
private boolean devmode;
@@ -43,10 +46,10 @@ public class BridgeSettings {
public void setVeraAddress(String veraAddress) {
this.veraaddress = veraAddress;
}
public String getHarmonyAddress() {
public IpList getHarmonyAddress() {
return harmonyaddress;
}
public void setHarmonyAddress(String harmonyaddress) {
public void setHarmonyAddress(IpList harmonyaddress) {
this.harmonyaddress = harmonyaddress;
}
public String getHarmonyUser() {
@@ -61,6 +64,12 @@ public class BridgeSettings {
public void setHarmonyPwd(String harmonypwd) {
this.harmonypwd = harmonypwd;
}
public Integer getUpnpResponseDevices() {
return upnpresponsedevices;
}
public void setUpnpResponseDevices(Integer upnpresponsedevices) {
this.upnpresponsedevices = upnpresponsedevices;
}
public boolean isUpnpStrict() {
return upnpstrict;
}
@@ -85,7 +94,8 @@ public class BridgeSettings {
return true;
}
public Boolean isValidHarmony() {
if(this.harmonyaddress.contains(Configuration.DEFAULT_HARMONY_ADDRESS))
List<NamedIP> devicesList = this.harmonyaddress.getDevices();
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_HARMONY_ADDRESS))
return false;
if(this.harmonypwd == null || this.harmonypwd == "")
return false;

View File

@@ -3,8 +3,10 @@ package com.bwssystems.HABridge;
public class Configuration {
public final static String DEVICE_DB_DIRECTORY = "data/device.db";
public final static String UPNP_RESPONSE_PORT = "50000";
public final static String UPNP_RESPONSE_DEVICES = "30";
public final static String DEFAULT_VERA_ADDRESS = "1.1.1.1";
public final static String DEFAULT_HARMONY_ADDRESS = "1.1.1.1";
public final static String DEFAULT_HARMONY_ADDRESS_LIST = "{devices:[{name:default,ip:1.1.1.1}]}";
public final static String DEFAULT_HARMONY_USER = "";
public final static String DEFAULT_HARMONY_PWD = "";
public final static String DFAULT_WEB_PORT = "8080";

View File

@@ -12,7 +12,8 @@ import com.bwssystems.HABridge.devicemanagmeent.*;
import com.bwssystems.HABridge.hue.HueMulator;
import com.bwssystems.HABridge.upnp.UpnpListener;
import com.bwssystems.HABridge.upnp.UpnpSettingsResource;
import com.bwssystems.harmony.HarmonyServer;
import com.bwssystems.harmony.HarmonyHome;
import com.google.gson.Gson;
public class HABridge {
@@ -34,7 +35,7 @@ public class HABridge {
public static void main(String[] args) {
Logger log = LoggerFactory.getLogger(HABridge.class);
DeviceResource theResources;
HarmonyServer myHarmonyServer;
HarmonyHome harmonyHome;
HueMulator theHueMulator;
UpnpSettingsResource theSettingResponder;
UpnpListener theUpnpListener;
@@ -61,13 +62,26 @@ public class HABridge {
bridgeSettings.setUpnpDeviceDb(System.getProperty("upnp.device.db", Configuration.DEVICE_DB_DIRECTORY));
bridgeSettings.setUpnpResponsePort(System.getProperty("upnp.response.port", Configuration.UPNP_RESPONSE_PORT));
bridgeSettings.setVeraAddress(System.getProperty("vera.address", Configuration.DEFAULT_VERA_ADDRESS));
bridgeSettings.setHarmonyAddress(System.getProperty("harmony.address", Configuration.DEFAULT_HARMONY_ADDRESS));
IpList theHarmonyList;
try {
theHarmonyList = new Gson().fromJson(System.getProperty("harmony.address", Configuration.DEFAULT_HARMONY_ADDRESS_LIST), IpList.class);
} catch (Exception e) {
try {
theHarmonyList = new Gson().fromJson("{devices:[{name:default,ip:" + System.getProperty("harmony.address", Configuration.DEFAULT_HARMONY_ADDRESS) + "}]}", IpList.class);
} catch (Exception et) {
log.error("Cannot parse harmony.address, Exiting with message: " + e.getMessage(), e);
return;
}
}
bridgeSettings.setHarmonyAddress(theHarmonyList);
bridgeSettings.setHarmonyUser(System.getProperty("harmony.user", Configuration.DEFAULT_HARMONY_USER));
bridgeSettings.setHarmonyPwd(System.getProperty("harmony.pwd", Configuration.DEFAULT_HARMONY_PWD));
bridgeSettings.setUpnpStrict(Boolean.parseBoolean(System.getProperty("upnp.strict", "true")));
bridgeSettings.setTraceupnp(Boolean.parseBoolean(System.getProperty("trace.upnp", "false")));
bridgeSettings.setDevMode(Boolean.parseBoolean(System.getProperty("dev.mode", "false")));
bridgeSettings.setUpnpResponseDevices(Integer.parseInt(System.getProperty("upnp.response.devices", Configuration.UPNP_RESPONSE_DEVICES)));
// sparkjava config directive to set ip address for the web server to listen on
// ipAddress("0.0.0.0"); // not used
// sparkjava config directive to set port for the web server to listen on
@@ -75,16 +89,11 @@ public class HABridge {
// sparkjava config directive to set html static file location for Jetty
staticFileLocation("/public");
//setup the harmony connection if available
try {
myHarmonyServer = HarmonyServer.setup(bridgeSettings);
} catch (Exception e) {
log.error("Cannot get harmony client setup, Exiting with message: " + e.getMessage(), e);
return;
}
harmonyHome = new HarmonyHome(bridgeSettings);
// setup the class to handle the resource setup rest api
theResources = new DeviceResource(bridgeSettings, theVersion, myHarmonyServer.getMyHarmony());
theResources = new DeviceResource(bridgeSettings, theVersion, harmonyHome);
// setup the class to handle the hue emulator rest api
theHueMulator = new HueMulator(theResources.getDeviceRepository(), myHarmonyServer.getMyHarmony());
theHueMulator = new HueMulator(bridgeSettings, theResources.getDeviceRepository(), harmonyHome);
theHueMulator.setupServer();
// setup the class to handle the upnp response rest api
theSettingResponder = new UpnpSettingsResource(bridgeSettings);

View File

@@ -0,0 +1,16 @@
package com.bwssystems.HABridge;
import java.util.List;
public class IpList {
private List<NamedIP> devices;
public List<NamedIP> getDevices() {
return devices;
}
public void setDevices(List<NamedIP> devices) {
this.devices = devices;
}
}

View File

@@ -0,0 +1,25 @@
package com.bwssystems.HABridge;
public class NamedIP {
private String name;
private String ip;
private String port;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public String getPort() {
return port;
}
public void setPort(String port) {
this.port = port;
}
}

View File

@@ -8,6 +8,7 @@ public class DeviceDescriptor{
private String mapId;
private String mapType;
private String deviceType;
private String targetDevice;
private String offUrl;
private String onUrl;
private String httpVerb;
@@ -47,7 +48,15 @@ public class DeviceDescriptor{
this.deviceType = deviceType;
}
public String getOffUrl() {
public String getTargetDevice() {
return targetDevice;
}
public void setTargetDevice(String targetDevice) {
this.targetDevice = targetDevice;
}
public String getOffUrl() {
return offUrl;
}

View File

@@ -187,6 +187,9 @@ public class DeviceRepository {
} else if (name.equals("deviceType")) {
deviceEntry.setDeviceType(reader.nextString());
log.debug("Read a Device - device json type:" + deviceEntry.getDeviceType());
} else if (name.equals("targetDevice")) {
deviceEntry.setTargetDevice(reader.nextString());
log.debug("Read a Device - device json type:" + deviceEntry.getTargetDevice());
} else if (name.equals("offUrl")) {
deviceEntry.setOffUrl(reader.nextString());
log.debug("Read a Device - device json off URL:" + deviceEntry.getOffUrl());

View File

@@ -20,7 +20,7 @@ import com.bwssystems.HABridge.JsonTransformer;
import com.bwssystems.HABridge.Version;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.dao.DeviceRepository;
import com.bwssystems.harmony.HarmonyHandler;
import com.bwssystems.harmony.HarmonyHome;
import com.bwssystems.luupRequests.Sdata;
import com.bwssystems.vera.VeraInfo;
import com.google.gson.Gson;
@@ -35,14 +35,16 @@ public class DeviceResource {
private DeviceRepository deviceRepository;
private VeraInfo veraInfo;
private Version version;
private HarmonyHandler myHarmonyHandler;
private HarmonyHome myHarmonyHome;
private static final Set<String> supportedVerbs = new HashSet<>(Arrays.asList("get", "put", "post"));
public DeviceResource(BridgeSettings theSettings, Version theVersion, HarmonyHandler myHarmony) {
super();
public DeviceResource(BridgeSettings theSettings, Version theVersion, HarmonyHome theHarmonyHome) {
this.deviceRepository = new DeviceRepository(theSettings.getUpnpDeviceDb());
this.veraInfo = new VeraInfo(theSettings.getVeraAddress(), theSettings.isValidVera());
this.myHarmonyHandler = myHarmony;
if(theSettings.isValidHarmony())
this.myHarmonyHome = theHarmonyHome;
else
this.myHarmonyHome = null;
this.version = theVersion;
setupEndpoints();
}
@@ -109,6 +111,7 @@ public class DeviceResource {
deviceEntry.setDeviceType(device.getDeviceType());
deviceEntry.setMapId(device.getMapId());
deviceEntry.setMapType(device.getMapType());
deviceEntry.setTargetDevice(device.getTargetDevice());
deviceEntry.setOnUrl(device.getOnUrl());
deviceEntry.setOffUrl(device.getOffUrl());
deviceEntry.setHttpVerb(device.getHttpVerb());
@@ -187,32 +190,32 @@ public class DeviceResource {
get (API_CONTEXT + "/harmony/activities", "application/json", (request, response) -> {
log.debug("Get harmony activities");
if(myHarmonyHandler == null) {
if(myHarmonyHome == null) {
response.status(HttpStatus.SC_NOT_FOUND);
return null;
}
response.status(HttpStatus.SC_OK);
return myHarmonyHandler.getActivities();
return myHarmonyHome.getActivities();
}, new JsonTransformer());
get (API_CONTEXT + "/harmony/show", "application/json", (request, response) -> {
log.debug("Get harmony current activity");
if(myHarmonyHandler == null) {
if(myHarmonyHome == null) {
response.status(HttpStatus.SC_NOT_FOUND);
return null;
}
response.status(HttpStatus.SC_OK);
return myHarmonyHandler.getCurrentActivity();
return myHarmonyHome.getCurrentActivities();
}, new JsonTransformer());
get (API_CONTEXT + "/harmony/devices", "application/json", (request, response) -> {
log.debug("Get harmony devices");
if(myHarmonyHandler == null) {
if(myHarmonyHome == null) {
response.status(HttpStatus.SC_NOT_FOUND);
return null;
}
response.status(HttpStatus.SC_OK);
return myHarmonyHandler.getDevices();
return myHarmonyHome.getDevices();
}, new JsonTransformer());
}

View File

@@ -1,5 +1,6 @@
package com.bwssystems.HABridge.hue;
import com.bwssystems.HABridge.BridgeSettings;
import com.bwssystems.HABridge.JsonTransformer;
import com.bwssystems.HABridge.api.UserCreateRequest;
import com.bwssystems.HABridge.api.hue.DeviceResponse;
@@ -8,6 +9,7 @@ import com.bwssystems.HABridge.api.hue.HueApiResponse;
import com.bwssystems.HABridge.dao.*;
import com.bwssystems.harmony.ButtonPress;
import com.bwssystems.harmony.HarmonyHandler;
import com.bwssystems.harmony.HarmonyHome;
import com.bwssystems.harmony.RunActivity;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -55,17 +57,22 @@ public class HueMulator {
private static final String HUE_CONTEXT = "/api";
private DeviceRepository repository;
private HarmonyHandler myHarmony;
private HarmonyHome myHarmonyHome;
private HttpClient httpClient;
private ObjectMapper mapper;
private BridgeSettings bridgeSettings;
public HueMulator(DeviceRepository aDeviceRepository, HarmonyHandler theHandler){
public HueMulator(BridgeSettings theBridgeSettings, DeviceRepository aDeviceRepository, HarmonyHome theHarmonyHome){
httpClient = HttpClients.createDefault();
mapper = new ObjectMapper(); //armzilla: work around Echo incorrect content type and breaking mapping. Map manually
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
repository = aDeviceRepository;
myHarmony = theHandler;
if(theBridgeSettings.isValidHarmony())
this.myHarmonyHome = theHarmonyHome;
else
this.myHarmonyHome = null;
bridgeSettings = theBridgeSettings;
}
// This function sets up the sparkjava rest calls for the hue api
@@ -74,6 +81,8 @@ public class HueMulator {
// http://ip_address:port/api/{userId}/lights returns json objects of all lights configured
get(HUE_CONTEXT + "/:userid/lights", "application/json", (request, response) -> {
String userId = request.params(":userid");
if(bridgeSettings.isTraceupnp())
log.info("Traceupnp: hue lights list requested: " + userId + " from " + request.ip());
log.debug("hue lights list requested: " + userId + " from " + request.ip());
List<DeviceDescriptor> deviceList = repository.findAll();
Map<String, DeviceResponse> deviceResponseMap = new HashMap<>();
@@ -101,6 +110,8 @@ public class HueMulator {
String newUser = null;
String aDeviceType = null;
if(bridgeSettings.isTraceupnp())
log.info("Traceupnp: hue api user create requested: " + request.body() + " from " + request.ip());
log.debug("hue api user create requested: " + request.body() + " from " + request.ip());
if(request.body() != null && !request.body().isEmpty()) {
@@ -113,6 +124,8 @@ public class HueMulator {
if(aDeviceType == null)
aDeviceType = "<not given>";
if(bridgeSettings.isTraceupnp())
log.info("Traceupnp: hue api user create requested for device type: " + aDeviceType + " and username: " + newUser);
log.debug("hue api user create requested for device type: " + aDeviceType + " and username: " + newUser);
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
@@ -241,26 +254,29 @@ public class HueMulator {
*/
String userId = request.params(":userid");
String lightId = request.params(":id");
log.debug("hue state change requested: " + userId + " from " + request.ip() + " body: " + request.body());
String responseString = null;
String url = null;
DeviceState state = null;
log.debug("hue state change requested: " + userId + " from " + request.ip() + " body: " + request.body());
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
response.type("application/json; charset=utf-8");
response.status(HttpStatus.SC_OK);
try {
state = mapper.readValue(request.body(), DeviceState.class);
} catch (IOException e) {
log.error("Object mapper barfed on input of body.", e);
response.status(HttpStatus.SC_BAD_REQUEST);
return null;
responseString = "[{\"error\":{\"type\": 2, \"address\": \"/lights/" + lightId + ",\"description\": \"Object mapper barfed on input of body.\"}}]";
return responseString;
}
DeviceDescriptor device = repository.findOne(lightId);
if (device == null) {
response.status(HttpStatus.SC_NOT_FOUND);
log.error("Could not find devcie: " + lightId + " for hue state change request: " + userId + " from " + request.ip() + " body: " + request.body());
return null;
log.error("Could not find device: " + lightId + " for hue state change request: " + userId + " from " + request.ip() + " body: " + request.body());
responseString = "[{\"error\":{\"type\": 3, \"address\": \"/lights/" + lightId + ",\"description\": \"Could not find device\", \"resource\": \"/lights/" + lightId + "\"}}]";
return responseString;
}
String responseString =null;
String url = null;
if (state.isOn()) {
responseString = "[{\"success\":{\"/lights/" + lightId + "/state/on\":true}}";
url = device.getOnUrl();
@@ -283,19 +299,32 @@ public class HueMulator {
}
else
responseString = responseString + "]";
if(device.getDeviceType().toLowerCase().contains("activity"))
{
log.debug("executing activity to Harmony: " + url);
RunActivity anActivity = new Gson().fromJson(url, RunActivity.class);
myHarmony.startActivity(anActivity);
HarmonyHandler myHarmony = myHarmonyHome.getHarmonyHandler(device.getTargetDevice());
if(myHarmony == null)
{
log.error("Should not get here, no harmony hub available");
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId + ",\"description\": \"Should not get here, no harmony hub available\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
}
else
myHarmony.startActivity(anActivity);
}
else if(device.getDeviceType().toLowerCase().contains("button"))
{
log.debug("executing button press to Harmony: " + url);
ButtonPress aDeviceButton = new Gson().fromJson(url, ButtonPress.class);
myHarmony.pressButton(aDeviceButton);
HarmonyHandler myHarmony = myHarmonyHome.getHarmonyHandler(device.getTargetDevice());
if(myHarmony == null)
{
log.error("Should not get here, no harmony hub available");
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId + ",\"description\": \"Should not get here, no harmony hub available\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
}
else
myHarmony.pressButton(aDeviceButton);
}
else
{
@@ -309,15 +338,11 @@ public class HueMulator {
body = replaceIntensityValue(device.getContentBodyOff(), state.getBri());
// make call
if (!doHttpRequest(url, device.getHttpVerb(), device.getContentType(), body)) {
response.status(HttpStatus.SC_SERVICE_UNAVAILABLE);
log.error("Error on calling url to change device state: " + url);
return null;
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId + ",\"description\": \"Error on calling url to change device state\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
}
}
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
response.type("application/json; charset=utf-8");
response.status(HttpStatus.SC_OK);
return responseString;
});
}

View File

@@ -40,9 +40,19 @@ public class UpnpSettingsResource {
+ "<depth>24</depth>\n" + "<url>hue_logo_3.png</url>\n" + "</icon>\n" + "</iconList>\n" + "</device>\n"
+ "</root>\n";
public UpnpSettingsResource(BridgeSettings theSettings) {
public UpnpSettingsResource(BridgeSettings theBridgeSettings) {
super();
this.theSettings = theSettings;
this.theSettings = new BridgeSettings();
this.theSettings.setDevMode(theBridgeSettings.isDevMode());
this.theSettings.setHarmonyAddress(theBridgeSettings.getHarmonyAddress());
this.theSettings.setServerPort(theBridgeSettings.getServerPort());
this.theSettings.setTraceupnp(theBridgeSettings.isTraceupnp());
this.theSettings.setUpnpConfigAddress(theBridgeSettings.getUpnpConfigAddress());
this.theSettings.setUpnpDeviceDb(theBridgeSettings.getUpnpDeviceDb());
this.theSettings.setUpnpResponseDevices(theBridgeSettings.getUpnpResponseDevices());
this.theSettings.setUpnpResponsePort(theBridgeSettings.getUpnpResponsePort());
this.theSettings.setUpnpStrict(theBridgeSettings.isUpnpStrict());
this.theSettings.setVeraAddress(theBridgeSettings.getVeraAddress());
}
public void setupServer() {

View File

@@ -0,0 +1,21 @@
package com.bwssystems.harmony;
import net.whistlingfish.harmony.config.Activity;
public class HarmonyActivity {
private String hub;
private Activity activity;
public String getHub() {
return hub;
}
public void setHub(String hub) {
this.hub = hub;
}
public Activity getActivity() {
return activity;
}
public void setActivity(Activity activity) {
this.activity = activity;
}
}

View File

@@ -0,0 +1,20 @@
package com.bwssystems.harmony;
import net.whistlingfish.harmony.config.Device;
public class HarmonyDevice {
private Device device;
private String hub;
public Device getDevice() {
return device;
}
public void setDevice(Device device) {
this.device = device;
}
public String getHub() {
return hub;
}
public void setHub(String hub) {
this.hub = hub;
}
}

View File

@@ -0,0 +1,115 @@
package com.bwssystems.harmony;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.BridgeSettings;
import com.bwssystems.HABridge.IpList;
import com.bwssystems.HABridge.NamedIP;
import net.whistlingfish.harmony.config.Activity;
import net.whistlingfish.harmony.config.Device;
public class HarmonyHome {
private static final Logger log = LoggerFactory.getLogger(HarmonyHome.class);
private Map<String, HarmonyServer> hubs;
public HarmonyHome(BridgeSettings bridgeSettings) {
super();
hubs = new HashMap<String, HarmonyServer>();
if(!bridgeSettings.isValidHarmony() && !bridgeSettings.isDevMode())
return;
if(bridgeSettings.isDevMode()) {
NamedIP devModeIp = new NamedIP();
devModeIp.setIp("10.10.10.10");
devModeIp.setName("devMode");
List<NamedIP> theList = new ArrayList<NamedIP>();
theList.add(devModeIp);
IpList thedevList = new IpList();
thedevList.setDevices(theList);
bridgeSettings.setHarmonyAddress(thedevList);
}
Iterator<NamedIP> theList = bridgeSettings.getHarmonyAddress().getDevices().iterator();
while(theList.hasNext()) {
NamedIP aHub = theList.next();
try {
hubs.put(aHub.getName(), HarmonyServer.setup(bridgeSettings, aHub));
} catch (Exception e) {
log.error("Cannot get harmony client (" + aHub.getName() + ") setup, Exiting with message: " + e.getMessage(), e);
return;
}
}
}
public HarmonyHandler getHarmonyHandler(String aName) {
HarmonyHandler aHandler = null;
if(aName == null || aName.equals("")) {
aName = "default";
}
if(hubs.get(aName) == null) {
Set<String> keys = hubs.keySet();
if(!keys.isEmpty()) {
aHandler = hubs.get(keys.toArray()[0]).getMyHarmony();
}
else
aHandler = null;
}
else
aHandler = hubs.get(aName).getMyHarmony();
return aHandler;
}
public List<HarmonyActivity> getActivities() {
Iterator<String> keys = hubs.keySet().iterator();
ArrayList<HarmonyActivity> activityList = new ArrayList<HarmonyActivity>();
while(keys.hasNext()) {
String key = keys.next();
Iterator<Activity> activities = hubs.get(key).getMyHarmony().getActivities().iterator();
while(activities.hasNext()) {
HarmonyActivity anActivity = new HarmonyActivity();
anActivity.setActivity(activities.next());
anActivity.setHub(key);
activityList.add(anActivity);
}
}
return activityList;
}
public List<HarmonyActivity> getCurrentActivities() {
Iterator<String> keys = hubs.keySet().iterator();
ArrayList<HarmonyActivity> activityList = new ArrayList<HarmonyActivity>();
while(keys.hasNext()) {
String key = keys.next();
Iterator<Activity> activities = hubs.get(key).getMyHarmony().getActivities().iterator();
while(activities.hasNext()) {
HarmonyActivity anActivity = new HarmonyActivity();
anActivity.setActivity(activities.next());
anActivity.setHub(key);
activityList.add(anActivity);
}
}
return activityList;
}
public List<HarmonyDevice> getDevices() {
Iterator<String> keys = hubs.keySet().iterator();
ArrayList<HarmonyDevice> deviceList = new ArrayList<HarmonyDevice>();
while(keys.hasNext()) {
String key = keys.next();
Iterator<Device> devices = hubs.get(key).getMyHarmony().getDevices().iterator();
while(devices.hasNext()) {
HarmonyDevice aDevice = new HarmonyDevice();
aDevice.setDevice(devices.next());
aDevice.setHub(key);
deviceList.add(aDevice);
}
}
return deviceList;
}
}

View File

@@ -8,6 +8,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.BridgeSettings;
import com.bwssystems.HABridge.NamedIP;
import com.google.inject.Guice;
import com.google.inject.Injector;
@@ -24,23 +25,25 @@ public class HarmonyServer {
private HarmonyHandler myHarmony;
private DevModeResponse devResponse;
private OAReplyProvider dummyProvider;
private NamedIP myNameAndIP;
private Logger log = LoggerFactory.getLogger(HarmonyServer.class);
public HarmonyServer() {
public HarmonyServer(NamedIP theHarmonyAddress) {
super();
myHarmony = null;
dummyProvider = null;
myNameAndIP = theHarmonyAddress;
}
public static HarmonyServer setup(BridgeSettings bridgeSettings) throws Exception {
if(!bridgeSettings.isValidHarmony()) {
return new HarmonyServer();
public static HarmonyServer setup(BridgeSettings bridgeSettings, NamedIP theHarmonyAddress) throws Exception {
if(!bridgeSettings.isValidHarmony() && !bridgeSettings.isDevMode()) {
return new HarmonyServer(theHarmonyAddress);
}
Injector injector = null;
if(!bridgeSettings.isDevMode())
injector = Guice.createInjector(new HarmonyClientModule());
HarmonyServer mainObject = new HarmonyServer();
HarmonyServer mainObject = new HarmonyServer(theHarmonyAddress);
if(!bridgeSettings.isDevMode())
injector.injectMembers(mainObject);
mainObject.execute(bridgeSettings);
@@ -70,7 +73,7 @@ public class HarmonyServer {
log.info(format("activity changed: [%d] %s", activity.getId(), activity.getLabel()));
}
});
harmonyClient.connect(mySettings.getHarmonyAddress(), mySettings.getHarmonyUser(), mySettings.getHarmonyPwd());
harmonyClient.connect(myNameAndIP.getIp(), mySettings.getHarmonyUser(), mySettings.getHarmonyPwd());
}
myHarmony = new HarmonyHandler(harmonyClient, noopCalls, devResponse);
}

View File

@@ -30,7 +30,7 @@ public class VeraInfo {
public VeraInfo(String addressString, Boolean isValidVera) {
super();
httpClient = HttpClients.createMinimal();
httpClient = HttpClients.createDefault();
veraAddressString = addressString;
validVera = isValidVera;
}

View File

@@ -29,6 +29,7 @@
<ul class="nav navbar-nav">
<li class="active"><a href="#">Home</a></li>
<li><a href="http://echo.amazon.com/#cards" target="_blank">My Echo</a></li>
<li><a href="https://github.com/bwssytems/ha-bridge/blob/master/README.md" target="_blank">Help</a></li>
<li class="dropdown">
<a id="dropdownMenu1" href="" class="dropdown-toggle"
data-toggle="dropdown" role="button" aria-haspopup="true"

View File

@@ -124,6 +124,31 @@ app.service('bridgeService', function ($http, $window, BridgeSettings) {
);
};
this.aContainsB = function (a, b) {
return a.indexOf(b) >= 0;
}
this.updateShowVera = function () {
if(this.aContainsB(self.BridgeSettings.veraaddress, "1.1.1.1") || self.BridgeSettings.veraaddress == "" || self.BridgeSettings.veraaddress == null)
this.state.showVera = false;
else
this.state.showVera = true;
return;
}
this.updateShowHarmony = function () {
if(self.BridgeSettings.harmonyaddress.devices) {
if(this.aContainsB(self.BridgeSettings.harmonyaddress.devices[0].ip, "1.1.1.1") || self.BridgeSettings.harmonyaddress == "" || self.BridgeSettings.harmonyaddress == null)
this.state.showHarmony = false;
else
this.state.showHarmony = true;
}
else
this.state.showHarmony = false;
return;
}
this.loadBridgeSettings = function () {
this.state.error = "";
return $http.get(this.state.upnpbase).then(
@@ -137,14 +162,6 @@ app.service('bridgeService', function ($http, $window, BridgeSettings) {
self.BridgeSettings.settraceupnp(response.data.traceupnp);
self.BridgeSettings.setupnpstrict(response.data.upnpstrict);
self.BridgeSettings.setdevmode(response.data.devmode);
if(self.BridgeSettings.veraaddress == "1.1.1.1" || self.BridgeSettings.veraaddress == "")
self.state.showVera = false;
else
self.state.showVera = true;
if(self.BridgeSettings.harmonyaddress == "1.1.1.1" || self.BridgeSettings.harmonyaddress == "")
self.state.showHarmony = false;
else
self.state.showHarmony = true;
},
function (error) {
if (error.data) {
@@ -157,22 +174,6 @@ app.service('bridgeService', function ($http, $window, BridgeSettings) {
);
};
this.updateShowVera = function () {
if(self.BridgeSettings.veraaddress == "1.1.1.1" || self.BridgeSettings.veraaddress == "")
this.state.showVera = false;
else
this.state.showVera = true;
return;
}
this.updateShowHarmony = function () {
if(self.BridgeSettings.harmonyaddress == "1.1.1.1" || self.BridgeSettings.harmonyaddress == "")
this.state.showHarmony = false;
else
this.state.showHarmony = true;
return;
}
this.viewVeraDevices = function () {
this.state.error = "";
if(!this.state.showVera)
@@ -246,9 +247,9 @@ app.service('bridgeService', function ($http, $window, BridgeSettings) {
);
};
this.findDeviceByMapId = function(id) {
this.findDeviceByMapId = function(id, target, type) {
for(var i = 0; i < this.state.devices.length; i++) {
if(this.state.devices[i].mapId == id)
if(this.state.devices[i].mapId == id && this.state.devices[i].mapType == type && this.state.devices[i].targetDevice == target)
return true;
}
return false;
@@ -266,6 +267,7 @@ app.service('bridgeService', function ($http, $window, BridgeSettings) {
mapId: device.mapId,
mapType: device.mapType,
deviceType: device.deviceType,
targetDevice: device.targetDevice,
onUrl: device.onUrl,
offUrl: device.offUrl,
httpVerb: device.httpVerb,
@@ -293,6 +295,7 @@ app.service('bridgeService', function ($http, $window, BridgeSettings) {
mapId: device.mapId,
mapType: device.mapType,
deviceType: device.deviceType,
targetDevice: device.targetDevice,
onUrl: device.onUrl,
offUrl: device.offUrl,
httpVerb: device.httpVerb,
@@ -328,9 +331,9 @@ app.service('bridgeService', function ($http, $window, BridgeSettings) {
);
};
this.deleteDeviceByMapId = function (id) {
this.deleteDeviceByMapId = function (id, type) {
for(var i = 0; i < this.state.devices.length; i++) {
if(this.state.devices[i].mapId == id)
if(this.state.devices[i].mapId == id && this.state.devices[i].mapType == type)
return self.deleteDevice(this.state.devices[i].id);
}
};
@@ -390,6 +393,9 @@ app.controller('ViewingController', function ($scope, $location, $http, $window,
bridgeService.state.base = url;
bridgeService.viewDevices();
};
$scope.goBridgeUrl = function (url) {
window.open(url, "_blank");
};
$scope.editDevice = function (device) {
bridgeService.editDevice(device);
$location.path('/editdevice');
@@ -499,7 +505,7 @@ app.controller('AddingController', function ($scope, $location, $http, bridgeSer
}
$scope.device.deviceType = "scene";
$scope.device.name = verascene.name;
$scope.devoce.mapType = "veraScene";
$scope.device.mapType = "veraScene";
$scope.device.mapId = verascene.id;
$scope.device.onUrl = $scope.vera.base + ":" + $scope.vera.port
+ "/data_request?id=action&output_format=json&serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&action=RunScene&SceneNum="
@@ -511,20 +517,22 @@ app.controller('AddingController', function ($scope, $location, $http, bridgeSer
$scope.buildActivityUrls = function (harmonyactivity) {
$scope.device.deviceType = "activity";
$scope.device.name = harmonyactivity.label;
$scope.device.targetDevice = harmonyactivity.hub;
$scope.device.name = harmonyactivity.activity.label;
$scope.device.mapType = "harmonyActivity";
$scope.device.mapId = harmonyactivity.id;
$scope.device.onUrl = "{\"name\":\"" + harmonyactivity.id + "\"}";
$scope.device.mapId = harmonyactivity.activity.id;
$scope.device.onUrl = "{\"name\":\"" + harmonyactivity.activity.id + "\"}";
$scope.device.offUrl = "{\"name\":\"-1\"}";
};
$scope.buildButtonUrls = function (harmonydevice, onbutton, offbutton) {
$scope.device.deviceType = "button";
$scope.device.name = harmonydevice.label;
$scope.device.targetDevice = harmonydevice.hub;
$scope.device.name = harmonydevice.device.label;
$scope.device.mapType = "harmonyButton";
$scope.device.mapId = harmonydevice.id + "-" + onbutton + "-" + offbutton;
$scope.device.onUrl = "{\"device\":\"" + harmonydevice.id + "\",\"button\":\"" + onbutton + "\"}";
$scope.device.offUrl = "{\"device\":\"" + harmonydevice.id + "\",\"button\":\"" + offbutton + "\"}";
$scope.device.mapId = harmonydevice.device.id + "-" + onbutton + "-" + offbutton;
$scope.device.onUrl = "{\"device\":\"" + harmonydevice.device.id + "\",\"button\":\"" + onbutton + "\"}";
$scope.device.offUrl = "{\"device\":\"" + harmonydevice.device.id + "\",\"button\":\"" + offbutton + "\"}";
};
$scope.testUrl = function (device, type) {
@@ -540,6 +548,7 @@ app.controller('AddingController', function ($scope, $location, $http, bridgeSer
$scope.device.name = "";
$scope.device.onUrl = "";
$scope.device.deviceType = "switch";
$scope.device.targetDevice = null;
$scope.device.offUrl = "";
$scope.device.httpVerb = null;
$scope.device.contentType = null;
@@ -584,19 +593,19 @@ app.controller('AddingController', function ($scope, $location, $http, bridgeSer
$scope.imgScenesUrl = "glyphicon glyphicon-plus";
};
$scope.deleteDeviceByMapId = function (id) {
bridgeService.deleteDeviceByMapId(id);
$scope.deleteDeviceByMapId = function (id, mapType) {
bridgeService.deleteDeviceByMapId(id, mapType);
};
});
app.filter('availableId', function(bridgeService) {
app.filter('availableHarmonyActivityId', 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].id)){
if(!bridgeService.findDeviceByMapId(input[i].activity.id, input[i].hub, "harmonyActivity")){
out.push(input[i]);
}
}
@@ -604,13 +613,13 @@ app.filter('availableId', function(bridgeService) {
}
});
app.filter('unavailableId', function(bridgeService) {
app.filter('unavailableHarmonyActivityId', 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].id)){
if(bridgeService.findDeviceByMapId(input[i].activity.id, input[i].hub, "harmonyActivity")){
out.push(input[i]);
}
}
@@ -618,6 +627,62 @@ app.filter('unavailableId', function(bridgeService) {
}
});
app.filter('availableVeraDeviceId', 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].id, null, "veraDevice")){
out.push(input[i]);
}
}
return out;
}
});
app.filter('unavailableVeraDeviceId', 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].id, null, "veraDevice")){
out.push(input[i]);
}
}
return out;
}
});
app.filter('availableVeraSceneId', 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].id, null, "veraScene")){
out.push(input[i]);
}
}
return out;
}
});
app.filter('unavailableVeraSceneId', 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].id, null, "veraScene")){
out.push(input[i]);
}
}
return out;
}
});
app.filter('configuredButtons', function() {
return function(input) {
var out = [];

View File

@@ -37,6 +37,9 @@
<th>
<a href="" ng-click="order('deviceType')">Type</a>
<span class="sortorder" ng-show="predicate === 'deviceType'" ng-class="{reverse:reverse}"></span></th>
<th>
<a href="" ng-click="order('targetDevice')">Target</a>
<span class="sortorder" ng-show="predicate === 'targetDevice'" ng-class="{reverse:reverse}"></span></th>
<th>Actions</th>
</tr>
</thead>
@@ -44,6 +47,7 @@
<td>{{device.id}}</td>
<td>{{device.name}}</td>
<td>{{device.deviceType}}</td>
<td>{{device.targetDevice}}</td>
<td>
<button class="btn btn-info" type="submit"
ng-click="testUrl(device, 'on')">Test ON</button>
@@ -66,7 +70,7 @@
<form class="form-horizontal">
<div class="form-group">
<label class="col-xs-12 col-sm-3 control-label" for="bridge-base">Bridge
<label class="col-xs-12 col-sm-2 control-label" for="bridge-base">Bridge
server</label>
<div class="col-xs-8 col-sm-7">
@@ -76,7 +80,7 @@
<button type="submit" class="col-xs-2 col-sm-1 btn btn-primary"
ng-click="setBridgeUrl(bridge.base)">Load</button>
<button type="submit" class="col-xs-2 col-sm-1 btn btn-primary"
ng-click="testUrl(bridge.base)">Go</button>
ng-click="goBridgeUrl(bridge.base)">Go</button>
</div>
</form>
<table class="table table-bordered table-striped table-hover">

View File

@@ -26,6 +26,15 @@
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary">
Update Device</button>
</div>
<div class="form-group">
<label class="col-xs-12 col-sm-2 control-label" for="device-target">Target
</label>
<div class="col-xs-8 col-sm-7">
<input type="text" class="form-control" id="device-target"
ng-model="device.targetDevice" placeholder="default">
</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

View File

@@ -26,13 +26,18 @@
<th>
<a href="" ng-click="order('id')">Id</a>
<span class="sortorder" ng-show="predicate === 'id'" ng-class="{reverse:reverse}"></span>
</th>
<th>
<a href="" ng-click="order('hub')">Hub</a>
<span class="sortorder" ng-show="predicate === 'hub'" ng-class="{reverse:reverse}"></span>
</th>
<th>Actions</th>
</tr>
</thead>
<tr ng-repeat="harmonyactivity in bridge.harmonyactivities | availableId | orderBy:predicate:reverse">
<td>{{harmonyactivity.label}}</td>
<td>{{harmonyactivity.id}}</td>
<tr ng-repeat="harmonyactivity in bridge.harmonyactivities | availableHarmonyActivityId | orderBy:predicate:reverse">
<td>{{harmonyactivity.activity.label}}</td>
<td>{{harmonyactivity.activity.id}}</td>
<td>{{harmonyactivity.hub}}</td>
<td>
<button class="btn btn-success" type="submit"
ng-click="buildActivityUrls(harmonyactivity)">Generate
@@ -57,15 +62,20 @@
<th>
<a href="" ng-click="order('id')">Id</a>
<span class="sortorder" ng-show="predicate === 'id'" ng-class="{reverse:reverse}"></span>
</th>
<th>
<a href="" ng-click="order('hub')">Hub</a>
<span class="sortorder" ng-show="predicate === 'hub'" ng-class="{reverse:reverse}"></span>
</th>
<th>Actions</th>
</tr>
</thead>
<tr ng-repeat="harmonyactivity in bridge.harmonyactivities | unavailableId | orderBy:predicate:reverse">
<td>{{harmonyactivity.label}}</td>
<td>{{harmonyactivity.id}}</td>
<tr ng-repeat="harmonyactivity in bridge.harmonyactivities | unavailableHarmonyActivityId | orderBy:predicate:reverse">
<td>{{harmonyactivity.activity.label}}</td>
<td>{{harmonyactivity.activity.id}}</td>
<td>{{harmonyactivity.hub}}</td>
<td><button class="btn btn-danger" type="submit"
ng-click="deleteDeviceByMapId(harmonyactivity.id)">Delete</button></td>
ng-click="deleteDeviceByMapId(harmonyactivity.activity.id, 'harmonyActivity')">Delete</button></td>
</tr>
</table>
</li>

View File

@@ -26,6 +26,10 @@
<th>
<a href="" ng-click="order('id')">Id</a>
<span class="sortorder" ng-show="predicate === 'id'" ng-class="{reverse:reverse}"></span>
</th>
<th>
<a href="" ng-click="order('hub')">Hub</a>
<span class="sortorder" ng-show="predicate === 'hub'" ng-class="{reverse:reverse}"></span>
</th>
<th>On Button</th>
<th>Off Button</th>
@@ -33,18 +37,19 @@
</tr>
</thead>
<tr ng-repeat="harmonydevice in bridge.harmonydevices | orderBy:predicate:reverse">
<td>{{harmonydevice.label}}</td>
<td>{{harmonydevice.id}}</td>
<td>{{harmonydevice.device.label}}</td>
<td>{{harmonydevice.device.id}}</td>
<td>{{harmonydevice.hub}}</td>
<td>
<select name="device-ctrlon" id="device-ctrlon" ng-model="devicectrlon">
<optgroup ng-repeat="ctrlon in harmonydevice.controlGroup" label="{{ctrlon.name}}">
<optgroup ng-repeat="ctrlon in harmonydevice.device.controlGroup" label="{{ctrlon.name}}">
<option ng-repeat="funcon in ctrlon.function">{{funcon.name}}</option>
</optgroup >
</select>
</td>
<td>
<select name="device-ctrloff" id="device-ctrloff" ng-model="devicectrloff">
<optgroup ng-repeat="ctrloff in harmonydevice.controlGroup" label="{{ctrloff.name}}">
<optgroup ng-repeat="ctrloff in harmonydevice.device.controlGroup" label="{{ctrloff.name}}">
<option ng-repeat="funcoff in ctrloff.function">{{funcoff.name}}</option>
</optgroup >
</select>
@@ -73,6 +78,10 @@
<th>
<a href="" ng-click="order('id')">Device Id</a>
<span class="sortorder" ng-show="predicate === 'id'" ng-class="{reverse:reverse}"></span>
</th>
<th>
<a href="" ng-click="order('targetDevice')">Hub</a>
<span class="sortorder" ng-show="predicate === 'targetDevice'" ng-class="{reverse:reverse}"></span>
</th>
<th>
<a href="" ng-click="order('mapId')">Harmony Device-Button On-Button Off</a>
@@ -84,10 +93,11 @@
<tr ng-repeat="device in bridge.devices | configuredButtons | orderBy:predicate:reverse">
<td>{{device.name}}</td>
<td>{{device.id}}</td>
<td>{{device.targetDevice}}</td>
<td>{{device.mapId}}</td>
<td>
<button class="btn btn-danger" type="submit"
ng-click="deleteDeviceByMapId(device.mapId)">Delete</button>
ng-click="deleteDeviceByMapId(device.mapId, device.mapType)">Delete</button>
</td>
</tr>
</table>

View File

@@ -45,7 +45,7 @@
<th>Actions</th>
</tr>
</thead>
<tr ng-repeat="veradevice in bridge.veradevices | availableId | orderBy:predicate:reverse">
<tr ng-repeat="veradevice in bridge.veradevices | availableVeraDeviceId | orderBy:predicate:reverse">
<td>{{veradevice.name}}</td>
<td>{{veradevice.id}}</td>
<td>{{veradevice.category}}</td>
@@ -86,14 +86,14 @@
<th>Actions</th>
</tr>
</thead>
<tr ng-repeat="veradevice in bridge.veradevices | unavailableId | orderBy:predicate:reverse">
<tr ng-repeat="veradevice in bridge.veradevices | unavailableVeraDeviceId | orderBy:predicate:reverse">
<td>{{veradevice.name}}</td>
<td>{{veradevice.id}}</td>
<td>{{veradevice.category}}</td>
<td>{{veradevice.room}}</td>
<td>
<button class="btn btn-danger" type="submit"
ng-click="deleteDeviceByMapId(harmonyactivity.id)">Delete</button>
ng-click="deleteDeviceByMapId(veradevice.id, 'veraDevice')">Delete</button>
</td>
</tr>
</table>

View File

@@ -34,7 +34,7 @@
<th>Actions</th>
</tr>
</thead>
<tr ng-repeat="verascene in bridge.verascenes | availableId | orderBy:predicate:reverse">
<tr ng-repeat="verascene in bridge.verascenes | availableVeraSceneId | orderBy:predicate:reverse">
<td>{{verascene.name}}</td>
<td>{{verascene.id}}</td>
<td>{{verascene.room}}</td>
@@ -70,13 +70,13 @@
<th>Actions</th>
</tr>
</thead>
<tr ng-repeat="verascene in bridge.verascenes | unavailableId | orderBy:predicate:reverse">
<tr ng-repeat="verascene in bridge.verascenes | unavailableVeraSceneId | orderBy:predicate:reverse">
<td>{{verascene.name}}</td>
<td>{{verascene.id}}</td>
<td>{{verascene.room}}</td>
<td>
<button class="btn btn-danger" type="submit"
ng-click="deleteDeviceByMapId(harmonyactivity.id)">Delete</button>
ng-click="deleteDeviceByMapId(verascene.id, 'veraScene')">Delete</button>
</td>
</tr>
</table>