Updated scrollable table header sorts for config, vera and harmony

Added upnp notification logic
This commit is contained in:
Admin
2017-01-09 17:28:41 -06:00
parent 6f544e1a7d
commit b644b5e3cc
9 changed files with 115 additions and 21 deletions

View File

@@ -5,7 +5,7 @@
<groupId>com.bwssystems.HABridge</groupId>
<artifactId>ha-bridge</artifactId>
<version>4beta3</version>
<version>4beta3.1</version>
<packaging>jar</packaging>
<name>HA Bridge</name>

View File

@@ -12,4 +12,5 @@ public class Configuration {
public static final String UPNP_MULTICAST_ADDRESS = "239.255.255.250";
public static final String CONFIG_FILE = "data/habridge.config";
public static final int NUMBER_OF_LOG_MESSAGES = 512;
public static final long UPNP_NOTIFY_TIMEOUT = 20000;
}

View File

@@ -12,7 +12,8 @@ import com.bwssystems.HABridge.util.UDPDatagramSender;
import java.io.IOException;
import java.net.*;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Enumeration;
import org.apache.http.conn.util.*;
@@ -25,6 +26,9 @@ public class UpnpListener {
private boolean strict;
private boolean traceupnp;
private BridgeControlDescriptor bridgeControl;
private String bridgeId;
private String bridgeSNUUID;
private HuePublicConfig aHueConfig;
private String responseTemplate1 = "HTTP/1.1 200 OK\r\n" +
"HOST: %s:%s\r\n" +
"CACHE-CONTROL: max-age=100\r\n" +
@@ -53,6 +57,16 @@ public class UpnpListener {
"ST: urn:schemas-upnp-org:device:basic:1\r\n" +
"USN: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n\r\n";
private String notifyTemplate = "NOTIFY * HTTP/1.1\r\n" +
"HOST: %s:%s\r\n" +
"CACHE-CONTROL: max-age=100\r\n" +
"LOCATION: http://%s:%s/description.xml\r\n" +
"SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/" + HueConstants.API_VERSION + "\r\n" +
"NTS: ssdp:alive\r\n" +
"hue-bridgeid: %s\r\n" +
"NT: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n" +
"USN: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n\r\n";
public UpnpListener(BridgeSettingsDescriptor theSettings, BridgeControlDescriptor theControl, UDPDatagramSender aUdpDatagramSender) {
super();
theUDPDatagramSender = aUdpDatagramSender;
@@ -61,6 +75,9 @@ public class UpnpListener {
strict = theSettings.isUpnpStrict();
traceupnp = theSettings.isTraceupnp();
bridgeControl = theControl;
aHueConfig = HuePublicConfig.createConfig("temp", responseAddress, HueConstants.HUB_VERSION);
bridgeId = aHueConfig.getBridgeid();
bridgeSNUUID = aHueConfig.getSNUUIDFromMac();
}
@SuppressWarnings("resource")
@@ -118,6 +135,13 @@ public class UpnpListener {
log.info("UPNP Discovery Listener running and ready....");
boolean loopControl = true;
boolean error = false;
try {
upnpMulticastSocket.setSoTimeout((int) Configuration.UPNP_NOTIFY_TIMEOUT);
} catch (SocketException e1) {
log.warn("Could not sent soTimeout on multi-cast socket");
}
Instant current, previous;
previous = Instant.now();
while (loopControl) { // trigger shutdown here
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
@@ -131,6 +155,15 @@ public class UpnpListener {
log.debug("UpnpListener send upnp exception: ", e);
}
}
current = Instant.now();
if(ChronoUnit.MILLIS.between(previous, current) > Configuration.UPNP_NOTIFY_TIMEOUT) {
sendUpnpNotify(socketAddress.getAddress(), upnpMulticastSocket);
previous = Instant.now();
}
} catch (SocketTimeoutException e) {
sendUpnpNotify(socketAddress.getAddress(), upnpMulticastSocket);
} catch (IOException e) {
log.error("UpnpListener encountered an error reading socket. Shutting down", e);
error = true;
@@ -198,11 +231,6 @@ public class UpnpListener {
protected void sendUpnpResponse(InetAddress requester, int sourcePort) throws IOException {
String discoveryResponse = null;
String bridgeId = null;
String bridgeSNUUID = null;
HuePublicConfig aHueConfig = HuePublicConfig.createConfig("temp", responseAddress, HueConstants.HUB_VERSION);
bridgeId = aHueConfig.getBridgeid();
bridgeSNUUID = aHueConfig.getSNUUIDFromMac();
discoveryResponse = String.format(responseTemplate1, Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT, responseAddress, httpServerPort, bridgeId, bridgeSNUUID);
if(traceupnp) {
log.info("Traceupnp: sendUpnpResponse discovery responseTemplate1 is <<<" + discoveryResponse + ">>>");
@@ -227,4 +255,21 @@ public class UpnpListener {
log.debug("sendUpnpResponse discovery responseTemplate3 is <<<" + discoveryResponse + ">>>");
theUDPDatagramSender.sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort);
}
protected void sendUpnpNotify(InetAddress aSocketAddress, MulticastSocket theUpnpMulticastSocket) {
String notifyData = null;
log.debug("Sending notify packet for upnp.");
notifyData = String.format(notifyTemplate, Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT, responseAddress, httpServerPort, bridgeId, bridgeSNUUID, bridgeSNUUID);
if(traceupnp) {
log.info("Traceupnp: sendUpnpNotify notifyTemplate is <<<" + notifyData + ">>>");
}
DatagramPacket notifyPacket = new DatagramPacket(notifyData.getBytes(), notifyData.length(), aSocketAddress, Configuration.UPNP_DISCOVERY_PORT);
try {
theUpnpMulticastSocket.send(notifyPacket);
} catch (IOException e1) {
log.warn("UpnpListener encountered an error sending upnp notify packet. IP: " + notifyPacket.getAddress().getHostAddress() + " with message: " + e1.getMessage());
log.debug("UpnpListener send upnp notify exception: ", e1);
}
}
}

View File

@@ -132,6 +132,12 @@ app.service ('bridgeService', function ($http, $window, ngToast) {
);
};
this.compareUniqueId = function(r1, r2) {
if (r1.id === r2.id)
return 0;
return parseInt(r1.id) > parseInt(r2.id) ? 1 : -1;
};
this.clearDevice = function () {
self.state.device = {};
self.state.olddevicename = "";
@@ -152,6 +158,43 @@ app.service ('bridgeService', function ($http, $window, ngToast) {
return a.indexOf(b) >= 0;
}
this.compareHarmonyNumber = function(r1, r2) {
if (r1.device !== undefined) {
if (r1.device.id === r2.device.id)
return 0;
return r1.device.id > r2.device.id ? 1 : -1;
}
if (r1.activity !== undefined) {
if (r1.activity.id === r2.activity.id)
return 0;
return r1.activity.id > r2.activity.id ? 1 : -1;
}
return 0;
};
this.compareHarmonyLabel = function(r1, r2) {
if (r1.device !== undefined) {
if (r1.device.label === r2.device.label)
return 0;
return r1.device.label > r2.device.label ? 1 : -1;
}
if (r1.activity !== undefined) {
if (r1.activity.label === r2.activity.label)
return 0;
return r1.activity.label > r2.activity.label ? 1 : -1;
}
return 0;
};
this.compareHarmonyHub = function(r1, r2) {
if (r1.hub !== undefined) {
if (r1.hub === r2.hub)
return 0;
return r1.hub > r2.hub ? 1 : -1;
}
return 0;
};
this.updateShowVera = function () {
this.state.showVera = self.state.settings.veraconfigured;
return;
@@ -961,6 +1004,7 @@ app.controller('ViewingController', function ($scope, $location, $http, $window,
$scope.imgUrl = "glyphicon glyphicon-plus";
$scope.visibleBk = false;
$scope.imgBkUrl = "glyphicon glyphicon-plus";
$scope.comparatorUniqueId = bridgeService.compareUniqueId;
$scope.testUrl = function (device, type) {
var dialogNeeded = false;
if((type === "on" && (bridgeService.aContainsB(device.onUrl, "${intensity.byte}") ||
@@ -1107,6 +1151,7 @@ app.controller('VeraController', function ($scope, $location, $http, bridgeServi
bridgeService.viewVeraScenes();
$scope.imgButtonsUrl = "glyphicon glyphicon-plus";
$scope.buttonsVisible = false;
$scope.comparatorUniqueId = bridgeService.compareUniqueId;
$scope.clearDevice = function () {
bridgeService.clearDevice();
@@ -1261,6 +1306,9 @@ app.controller('HarmonyController', function ($scope, $location, $http, bridgeSe
bridgeService.viewHarmonyDevices();
$scope.imgButtonsUrl = "glyphicon glyphicon-plus";
$scope.buttonsVisible = false;
$scope.comparatorNumber = bridgeService.compareHarmonyNumber;
$scope.comparatorLabel = bridgeService.compareHarmonyLabel;
$scope.comparatorHub = bridgeService.compareHarmonyHub;
$scope.clearDevice = function () {
bridgeService.clearDevice();
@@ -2352,7 +2400,7 @@ app.filter('unavailableHalDeviceId', function (bridgeService) {
if(input === undefined || input === null || input.length === undefined)
return out;
for (var i = 0; i < input.length; i++) {
if(input[i].mapType !== null && bridgeService.aContainsB(input[i].mapType, "hal")){
if(input[i].mapType !== undefined && input[i].mapType !== null && bridgeService.aContainsB(input[i].mapType, "hal")){
out.push(input[i]);
}
}
@@ -2366,7 +2414,7 @@ app.filter('configuredButtons', function () {
if(input === undefined || input === null || input.length === undefined)
return out;
for (var i = 0; i < input.length; i++) {
if(input[i].mapType === "harmonyButton"){
if(input[i].mapType !== undefined && input[i].mapType === "harmonyButton"){
out.push(input[i]);
}
}
@@ -2380,7 +2428,7 @@ app.filter('configuredMqttMsgs', function () {
if(input === undefined || input === null || input.length === undefined)
return out;
for (var i = 0; i < input.length; i++) {
if(input[i].mapType === "mqttMessage"){
if(input[i].mapType !== undefined && input[i].mapType === "mqttMessage"){
out.push(input[i]);
}
}
@@ -2408,7 +2456,7 @@ app.filter('unavailableHassDeviceId', function (bridgeService) {
if(input === undefined || input === null || input.length === undefined)
return out;
for (var i = 0; i < input.length; i++) {
if(input[i].mapType !== null && bridgeService.aContainsB(input[i].mapType, "hass")){
if(input[i].mapType !== undefined && input[i].mapType !== null && bridgeService.aContainsB(input[i].mapType, "hass")){
out.push(input[i]);
}
}

View File

@@ -37,7 +37,7 @@
<thead>
<tr>
<th>Row</th>
<th sortable-header col="id">ID</th>
<th sortable-header col="id" comparator-fn="comparatorUniqueId">ID</th>
<th sortable-header col="name">Name</th>
<th sortable-header col="deviceType">Type</th>
<th sortable-header col="targetDevice">Target</th>
@@ -72,7 +72,7 @@
<div class="panel-heading">
<h1 class="panel-title">
Bridge Device DB Backup <a ng-click="toggleBk()"><span
class={{imgBkUrl}} aria-hidden="true"></a>
class={{imgBkUrl}} aria-hidden="true"></span></a>
</h1>
</div>
<div ng-if="visibleBk" class="animate-if" class="panel-body">

View File

@@ -38,9 +38,9 @@
<thead>
<tr>
<th>Row</th>
<th sortable-header col="name">Name</th>
<th sortable-header col="id">Id</th>
<th sortable-header col="hub">Hub</th>
<th sortable-header col="label" comparator-fn="comparatorLabel">Name</th>
<th sortable-header col="id" comparator-fn="comparatorNumber">Id</th>
<th sortable-header col="hub" comparator-fn="comparatorHub">Hub</th>
<th>Actions</th>
</tr>
</thead>

View File

@@ -41,9 +41,9 @@
<thead>
<tr>
<th>Row</th>
<th sortable-header col="name">Name</th>
<th sortable-header col="id">Id</th>
<th sortable-header col="hub">Hub</th>
<th sortable-header col="label" comparator-fn="comparatorLabel">Name</th>
<th sortable-header col="id" comparator-fn="comparatorNumber">Id</th>
<th sortable-header col="hub" comparator-fn="comparatorHub">Hub</th>
<th>On Button</th>
<th>Off Button</th>
<th>Actions</th>

View File

@@ -55,7 +55,7 @@
value="{{selectAll}}"
ng-checked="selectAll"
ng-click="toggleSelectAll()"> Name</span></th>
<th sortable-header col="id">Id</th>
<th sortable-header col="id" comparator-fn="comparatorUniqueId">Id</th>
<th sortable-header col="category">Category</th>
<th sortable-header col="room">Room</th>
<th sortable-header col="veraname">Vera</th>

View File

@@ -38,7 +38,7 @@
<tr>
<th>Row</th>
<th sortable-header col="name">Name</th>
<th sortable-header col="id">Id</th>
<th sortable-header col="id" comparator-fn="comparatorUniqueId">Id</th>
<th sortable-header col="room">Room</th>
<th sortable-header col="veraname">Vera</th>
<th>Actions</th>