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.
This commit is contained in:
Admin
2016-05-24 16:42:05 -05:00
parent ed3db4427b
commit 7f816b03d5
13 changed files with 189 additions and 36 deletions

View File

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

View File

@@ -5,7 +5,7 @@
<groupId>com.bwssystems.HABridge</groupId>
<artifactId>ha-bridge</artifactId>
<version>2.0.7-hal-a</version>
<version>2.0.7-hal-b</version>
<packaging>jar</packaging>
<name>HA Bridge</name>

View File

@@ -35,26 +35,46 @@ public class HalHome {
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();
List<HalDevice> theResponse = hals.get(key).getLights();
if(theResponse != null) {
Iterator<HalDevice> 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<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.setHaladdress(hals.get(theKey).getHalAddress().getIp());
aNewHalDevice.setHalname(theKey);
theDeviceList.add(aNewHalDevice);
}
return true;
}
}

View File

@@ -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<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);
}
private List<HalDevice> getHalDevices(String apiType, String deviceType) {
DeviceElements theHalApiResponse = null;
List<HalDevice> 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<HalDevice>();
Iterator<DeviceName> 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;
}

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

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

View File

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

View File

@@ -61,7 +61,7 @@
</table>
</scrollable-table>
</div>
<div class="panel panel-default backup">
<div class="panel panel-default">
<div class="panel-heading">
<h1 class="panel-title">
Bridge Device DB Backup <a ng-click="toggleBk()"><span
@@ -69,6 +69,7 @@
</h1>
</div>
<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">
<div class="form-group">
<label class="col-xs-12 col-sm-2 control-label" for="backup-name">Backup

View File

@@ -96,6 +96,7 @@
<option value="nestHomeAway">Nest Home Status</option>
<option value="nestThermoSet">Nest Thermostat</option>
<option value="hueDevice">Hue Device</option>
<option value="halDevice">HAL Device</option>
</select>
</div>
<button class="btn btn-danger" ng-click="clearDevice()">

View File

@@ -50,7 +50,11 @@
<thead>
<tr>
<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="category">Category</th>
<th sortable-header col="halname">HAL</th>
<th>Actions</th>

View File

@@ -40,7 +40,10 @@
<thead>
<tr>
<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="huename">Hue</th>
<th>Actions</th>

View File

@@ -284,6 +284,7 @@
</h1>
</div>
<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">
<div class="form-group">
<label class="col-xs-12 col-sm-2 control-label" for="backup-name">Backup

View File

@@ -49,7 +49,10 @@
<thead>
<tr>
<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="category">Category</th>
<th sortable-header col="room">Room</th>