From 7f816b03d55e12b910fc0e57dadd1e56c8833ce8 Mon Sep 17 00:00:00 2001 From: Admin Date: Tue, 24 May 2016 16:42:05 -0500 Subject: [PATCH] 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. --- README.md | 16 ++-- pom.xml | 2 +- src/main/java/com/bwssystems/hal/HalHome.java | 46 +++++++---- src/main/java/com/bwssystems/hal/HalInfo.java | 40 +++++++++- .../com/bwssystems/hal/StatusDescription.java | 18 +++++ .../resources/public/css/scrollable-table.css | 5 +- src/main/resources/public/scripts/app.js | 77 +++++++++++++++++-- .../resources/public/views/configuration.html | 3 +- .../resources/public/views/editdevice.html | 1 + .../resources/public/views/haldevice.html | 6 +- .../resources/public/views/huedevice.html | 5 +- src/main/resources/public/views/system.html | 1 + .../resources/public/views/veradevice.html | 5 +- 13 files changed, 189 insertions(+), 36 deletions(-) create mode 100644 src/main/java/com/bwssystems/hal/StatusDescription.java diff --git a/README.md b/README.md index 6fb439a..bc75ba0 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Then locate the jar and start the server with: ATTENTION: This requires JDK 1.8 to run ``` -java -jar ha-bridge-2.0.6.jar +java -jar ha-bridge-2.5.0.jar ``` ### Automation on Linux systems To have this configured and running automatically there are a few resources to use. One is using Docker and a docker container has been built for this and can be gotten here: https://github.com/aptalca/docker-ha-bridge @@ -35,7 +35,7 @@ After=network.target [Service] Type=simple -ExecStart=/usr/bin/java -jar -Dconfig.file=/home/pi/amazon-echo/data/habridge.config /home/pi/amazon-echo/ha-bridge-2.0.6.jar +ExecStart=/usr/bin/java -jar -Dconfig.file=/home/pi/amazon-echo/data/habridge.config /home/pi/amazon-echo/ha-bridge-2.5.0.jar [Install] WantedBy=multi-user.target @@ -43,11 +43,11 @@ WantedBy=multi-user.target Basic script setup to run the bridge on a pi. -Create the directory and make sure that ha-bridge-2.0.6.jar is in your /home/pi/habridge directory. +Create the directory and make sure that ha-bridge-2.5.0.jar is in your /home/pi/habridge directory. ``` pi@raspberrypi:~ $ mkdir habridge pi@raspberrypi:~ $ cd habridge -pi@raspberrypi:~/habridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v2.0.6/ha-bridge-2.0.6.jar +pi@raspberrypi:~/habridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v2.0.6/ha-bridge-2.5.0.jar ``` Edit the shell script for starting: ``` @@ -57,7 +57,7 @@ Then cut and past this, modify any locations that are not correct ``` cd /home/pi/habridge rm /home/pi/habridge/habridge-log.txt -nohup java -jar /home/pi/habridge/ha-bridge-2.0.6.jar > /home/pi/habridge/habridge-log.txt 2>&1 & +nohup java -jar /home/pi/habridge/ha-bridge-2.5.0.jar > /home/pi/habridge/habridge-log.txt 2>&1 & chmod 777 /home/pi/habridge/habridge-log.txt ``` Exit and save the file with ctrl-X and follow the prompts and then execute on the command line: @@ -109,7 +109,7 @@ The server defaults to running on port 8080. To override what the default is, sp #### UPNP Response Port The upnp response port that will be used. The default is 50000. #### Vera Names and IP Addresses -Provide IP Addresses of your Veras that you want to utilize with the bridge. Also, give a meaningful name to each one so it is easy to decipher in the helper tab. When these names and IP's are given, the bridge will be able to control the devices or scenes by the call it receives and send it to the target Vera and devce/scene you configure. +Provide IP Addresses of your Veras that you want to utilize with the bridge. Also, give a meaningful name to each one so it is easy to decipher in the helper tab. When these names and IP's are given, the bridge will be able to control the devices or scenes by the call it receives and send it to the target Vera and device/scene you configure. #### Harmony Names and IP Addresses Provide IP Addresses of your Harmony Hubs that you want to utilize with the bridge. Also, give a meaningful name to each one so it is easy to decipher in the helper tab. When these names and IP's are given, the bridge will be able to control the activity or buttons by the call it receives and send it to the target Harmony Hub and activity/button you configure. #### Harmony Username @@ -120,6 +120,10 @@ The password for the user name of the MyHarmony.com account for the Harmony Hub. Provide IP Addresses of your Hue Bridges that you want to proxy through the bridge. Also, give a meaningful name to each one so it is easy to decipher in the helper tab. When these names and IP's are given, the bridge will passthru the call it receives to the target Hue and device you configure. Don't forget - You will need to push the link button when you got to the Hue Tab the first time ater the process comes up. (The user name is not persistent when the process comes up.) +#### HAL Names and IP Addresses +Provide IP Addresses of your HAL Systems that you want to utilize with the bridge. Also, give a meaningful name to each one so it is easy to decipher in the helper tab. When these names and IP's are given, the bridge will be able to control the devices or scenes by the call it receives and send it to the target HAL and device/scene you configure. +#### HAL Token +The token you generate or give to a HAL and must be the same for all HAL's you have identified. This needs to be given if you are using the HAL features. #### Nest Username The user name of the home.nest.com account for the Nest user. This needs to be given if you are using the Nest features. There is no need to give any ip address or host information as this contacts your cloud account. #### Nest Password diff --git a/pom.xml b/pom.xml index e7910e7..710f8a6 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.bwssystems.HABridge ha-bridge - 2.0.7-hal-a + 2.0.7-hal-b jar HA Bridge diff --git a/src/main/java/com/bwssystems/hal/HalHome.java b/src/main/java/com/bwssystems/hal/HalHome.java index ddfc1b3..6988fbb 100644 --- a/src/main/java/com/bwssystems/hal/HalHome.java +++ b/src/main/java/com/bwssystems/hal/HalHome.java @@ -35,26 +35,46 @@ public class HalHome { public List getDevices() { log.debug("consolidating devices for hues"); + List theResponse = null; Iterator keys = hals.keySet().iterator(); List deviceList = new ArrayList(); while(keys.hasNext()) { String key = keys.next(); - List theResponse = hals.get(key).getLights(); - if(theResponse != null) { - Iterator devices = theResponse.iterator(); - while(devices.hasNext()) { - HalDevice theDevice = devices.next(); - HalDevice aNewHalDevice = new HalDevice(); - aNewHalDevice.setHaldevicetype(theDevice.getHaldevicetype()); - aNewHalDevice.setHaldevicename(theDevice.getHaldevicename()); - aNewHalDevice.setHaladdress(hals.get(key).getHalAddress().getIp()); - aNewHalDevice.setHalname(key); - deviceList.add(aNewHalDevice); - } - } + theResponse = hals.get(key).getLights(); + if(theResponse != null) + addHalDevices(deviceList, theResponse, key); else log.warn("Cannot get lights for Hal with name: " + key); + 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); } return deviceList; } + + private Boolean addHalDevices(List theDeviceList, List theSourceList, String theKey) { + Iterator devices = theSourceList.iterator(); + while(devices.hasNext()) { + HalDevice theDevice = devices.next(); + HalDevice aNewHalDevice = new HalDevice(); + aNewHalDevice.setHaldevicetype(theDevice.getHaldevicetype()); + aNewHalDevice.setHaldevicename(theDevice.getHaldevicename()); + aNewHalDevice.setHaladdress(hals.get(theKey).getHalAddress().getIp()); + aNewHalDevice.setHalname(theKey); + theDeviceList.add(aNewHalDevice); + } + return true; + } } diff --git a/src/main/java/com/bwssystems/hal/HalInfo.java b/src/main/java/com/bwssystems/hal/HalInfo.java index 1461595..d9016d5 100644 --- a/src/main/java/com/bwssystems/hal/HalInfo.java +++ b/src/main/java/com/bwssystems/hal/HalInfo.java @@ -19,7 +19,13 @@ import com.google.gson.Gson; public class HalInfo { private static final Logger log = LoggerFactory.getLogger(HalInfo.class); - private static final String LIGHTS_REQUEST = "/DeviceData!DeviceCmd=GetNames!DeviceType=Light?Token="; + private static final String DEVICE_REQUEST = "/DeviceData!DeviceCmd=GetNames!DeviceType="; + 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 HttpClient httpClient; private NamedIP halAddress; private String theToken; @@ -32,30 +38,56 @@ public class HalInfo { } public List getLights() { + return getHalDevices(DEVICE_REQUEST + LIGHT_REQUEST + TOKEN_REQUEST, LIGHT_REQUEST); + } + + public List getAppliances() { + return getHalDevices(DEVICE_REQUEST + APPL_REQUEST + TOKEN_REQUEST, APPL_REQUEST); + } + + public List getTheatre() { + return getHalDevices(DEVICE_REQUEST + THEATRE_REQUEST + TOKEN_REQUEST, THEATRE_REQUEST); + } + + public List getCustom() { + return getHalDevices(DEVICE_REQUEST + CUSTOM_REQUEST + TOKEN_REQUEST, CUSTOM_REQUEST); + } + + private List getHalDevices(String apiType, String deviceType) { DeviceElements theHalApiResponse = null; List deviceList = null; String theUrl = null; String theData; - theUrl = "http://" + halAddress.getIp() + LIGHTS_REQUEST + theToken; + theUrl = "http://" + halAddress.getIp() + apiType + theToken; theData = doHttpGETRequest(theUrl); if(theData != null) { log.debug("GET 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(); Iterator theDeviceNames = theHalApiResponse.getDeviceElements().iterator(); while(theDeviceNames.hasNext()) { DeviceName theDevice = theDeviceNames.next(); HalDevice aNewHalDevice = new HalDevice(); - aNewHalDevice.setHaldevicetype("lights"); + aNewHalDevice.setHaldevicetype(deviceType); aNewHalDevice.setHaldevicename(theDevice.getDeviceName()); deviceList.add(aNewHalDevice); } } else { - log.warn("GET HalApiResponse for " + halAddress.getName() + " - returned null, no data."); + log.warn("Get Hal device types " + deviceType + " for " + halAddress.getName() + " - returned null, no data."); } return deviceList; } diff --git a/src/main/java/com/bwssystems/hal/StatusDescription.java b/src/main/java/com/bwssystems/hal/StatusDescription.java new file mode 100644 index 0000000..46c9a43 --- /dev/null +++ b/src/main/java/com/bwssystems/hal/StatusDescription.java @@ -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; + } +} diff --git a/src/main/resources/public/css/scrollable-table.css b/src/main/resources/public/css/scrollable-table.css index 7d17c86..39364c0 100644 --- a/src/main/resources/public/css/scrollable-table.css +++ b/src/main/resources/public/css/scrollable-table.css @@ -1,5 +1,5 @@ .scrollableContainer { - height: 600px; + max-height: 436px; /* sets max-height value for all standards-compliant browsers */ position: relative; padding-top: 35px; overflow: hidden; @@ -28,7 +28,8 @@ } .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-y: auto; border: 1px solid #d5d5d5; diff --git a/src/main/resources/public/scripts/app.js b/src/main/resources/public/scripts/app.js index 244ec40..2dcc002 100644 --- a/src/main/resources/public/scripts/app.js +++ b/src/main/resources/public/scripts/app.js @@ -864,12 +864,20 @@ app.controller('DeleteMapandIdDialogCtrl', function ($scope, bridgeService, ngDi ngDialog.close('ngdialog1'); bridgeService.deleteDeviceByMapId(mapandid.id, mapandid.mapType); bridgeService.viewDevices(); - bridgeService.viewVeraDevices(); - bridgeService.viewVeraScenes(); - bridgeService.viewHarmonyActivities(); - bridgeService.viewHarmonyDevices(); - bridgeService.viewNestItems(); - bridgeService.viewHueDevices(); + 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; }; }); @@ -879,6 +887,7 @@ app.controller('VeraController', function ($scope, $location, $http, bridgeServi $scope.device = $scope.bridge.device; $scope.device_dim_control = ""; $scope.bulk = { devices: [] }; + $scope.selectAll = false; var veraList = angular.fromJson($scope.bridge.settings.veraaddress); if(veraList != null) $scope.vera = {base: "http://" + veraList.devices[0].ip, port: "3480", id: ""}; @@ -985,6 +994,7 @@ app.controller('VeraController', function ($scope, $location, $http, bridgeServi } ); $scope.bulk = { devices: [] }; + $scope.selectAll = false; }; $scope.toggleSelection = function toggleSelection(deviceId) { @@ -993,11 +1003,28 @@ app.controller('VeraController', function ($scope, $location, $http, bridgeServi // 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.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); + } } }; @@ -1226,6 +1253,7 @@ app.controller('HueController', function ($scope, $location, $http, bridgeServic $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; @@ -1298,6 +1326,7 @@ app.controller('HueController', function ($scope, $location, $http, bridgeServic ); $scope.bulk = { devices: [] }; + $scope.selectAll = false; }; $scope.toggleSelection = function toggleSelection(deviceId) { @@ -1306,11 +1335,28 @@ app.controller('HueController', function ($scope, $location, $http, bridgeServic // 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); + } } }; @@ -1338,6 +1384,7 @@ app.controller('HalController', function ($scope, $location, $http, bridgeServic $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; @@ -1432,6 +1479,7 @@ app.controller('HalController', function ($scope, $location, $http, bridgeServic } ); $scope.bulk = { devices: [] }; + $scope.selectAll = false; }; $scope.toggleSelection = function toggleSelection(deviceId) { @@ -1440,11 +1488,28 @@ app.controller('HalController', function ($scope, $location, $http, bridgeServic // 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); + } } }; diff --git a/src/main/resources/public/views/configuration.html b/src/main/resources/public/views/configuration.html index cf88e99..5a7c61d 100644 --- a/src/main/resources/public/views/configuration.html +++ b/src/main/resources/public/views/configuration.html @@ -61,7 +61,7 @@ -
+

Bridge Device DB Backup

+

Control your backups from this area. Use the default name by hitting backup or specify your own.

+

Control your backups from this area. Use the default name by hitting backup or specify your own.