Compare commits

...

5 Commits

Author SHA1 Message Date
BWS Systems
0205633684 Update version to next release as the tag is on the wrong branch 2019-06-25 09:49:55 -05:00
BWS Systems
7b48590807 updated upnp notify to add root and basic schemas 2019-06-25 09:27:10 -05:00
BWS Systems
5f7cd70710 Added back to top button on long scroll 2019-06-17 13:04:07 -05:00
BWS Systems
46ad4489ad Finish HomeAssistant auth changes and implement no scroll for pages 2019-06-14 10:32:15 -05:00
BWS Systems
bfd1b94473 Start adding new Bearer Token for Home Assistant 2019-06-13 15:51:49 -05:00
8 changed files with 665 additions and 655 deletions

View File

@@ -5,7 +5,7 @@
<groupId>com.bwssystems.HABridge</groupId> <groupId>com.bwssystems.HABridge</groupId>
<artifactId>ha-bridge</artifactId> <artifactId>ha-bridge</artifactId>
<version>5.3.0RC2</version> <version>5.3.0RC5</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>HA Bridge</name> <name>HA Bridge</name>

View File

@@ -0,0 +1,13 @@
package com.bwssystems.HABridge.plugins.hass;
public class HassAuth {
boolean legacyauth;
public boolean isLegacyauth() {
return legacyauth;
}
public void setLegacyauth(boolean legacyauth) {
this.legacyauth = legacyauth;
}
}

View File

@@ -19,11 +19,16 @@ public class HomeAssistant {
private static final Logger log = LoggerFactory.getLogger(HomeAssistant.class); private static final Logger log = LoggerFactory.getLogger(HomeAssistant.class);
private NamedIP hassAddress; private NamedIP hassAddress;
private HTTPHandler anHttpHandler; private HTTPHandler anHttpHandler;
private HassAuth theAuthType;
private NameValue[] headers;
public HomeAssistant(NamedIP addressName) { public HomeAssistant(NamedIP addressName) {
super(); super();
anHttpHandler = HTTPHome.getHandler(); anHttpHandler = HTTPHome.getHandler();
hassAddress = addressName; hassAddress = addressName;
theAuthType = null;
headers = null;
isLegacyAuth();
} }
public NamedIP getHassAddress() { public NamedIP getHassAddress() {
@@ -35,8 +40,8 @@ public class HomeAssistant {
} }
public Boolean callCommand(HassCommand aCommand) { public Boolean callCommand(HassCommand aCommand) {
log.debug("calling HomeAssistant: " + aCommand.getHassName() + " - " log.debug("calling HomeAssistant: " + aCommand.getHassName() + " - " + aCommand.getEntityId() + " - "
+ aCommand.getEntityId() + " - " + aCommand.getState() + " - " + aCommand.getBri()); + aCommand.getState() + " - " + aCommand.getBri());
String aUrl = null; String aUrl = null;
String domain = aCommand.getEntityId().substring(0, aCommand.getEntityId().indexOf(".")); String domain = aCommand.getEntityId().substring(0, aCommand.getEntityId().indexOf("."));
aUrl = hassAddress.getHttpPreamble() + "/api/services/"; aUrl = hassAddress.getHttpPreamble() + "/api/services/";
@@ -45,22 +50,14 @@ public class HomeAssistant {
else else
aUrl = aUrl + domain; aUrl = aUrl + domain;
String aBody = "{\"entity_id\":\"" + aCommand.getEntityId() + "\""; String aBody = "{\"entity_id\":\"" + aCommand.getEntityId() + "\"";
NameValue[] headers = null; headers = getAuthHeader();
if(hassAddress.getPassword() != null && !hassAddress.getPassword().isEmpty()) {
NameValue password = new NameValue();
password.setName("x-ha-access");
password.setValue(hassAddress.getPassword());
headers = new NameValue[1];
headers[0] = password;
}
if (aCommand.getState().equalsIgnoreCase("on")) { if (aCommand.getState().equalsIgnoreCase("on")) {
aUrl = aUrl + "/turn_on"; aUrl = aUrl + "/turn_on";
if (aCommand.getBri() != null) if (aCommand.getBri() != null)
aBody = aBody + ",\"brightness\":" + aCommand.getBri() + "}"; aBody = aBody + ",\"brightness\":" + aCommand.getBri() + "}";
else else
aBody = aBody + "}"; aBody = aBody + "}";
} } else {
else {
aUrl = aUrl + "/turn_off"; aUrl = aUrl + "/turn_off";
aBody = aBody + "}"; aBody = aBody + "}";
} }
@@ -75,14 +72,7 @@ public class HomeAssistant {
State[] theHassStates; State[] theHassStates;
String theUrl = null; String theUrl = null;
String theData; String theData;
NameValue[] headers = null; headers = getAuthHeader();
if(hassAddress.getPassword() != null && !hassAddress.getPassword().isEmpty()) {
NameValue password = new NameValue();
password.setName("x-ha-access");
password.setValue(hassAddress.getPassword());
headers = new NameValue[1];
headers[0] = password;
}
if (hassAddress.getSecure() != null && hassAddress.getSecure()) if (hassAddress.getSecure() != null && hassAddress.getSecure())
theUrl = "https"; theUrl = "https";
else else
@@ -93,20 +83,50 @@ public class HomeAssistant {
log.debug("GET Hass States - data: " + theData); log.debug("GET Hass States - data: " + theData);
theHassStates = new Gson().fromJson(theData, State[].class); theHassStates = new Gson().fromJson(theData, State[].class);
if (theHassStates == null) { if (theHassStates == null) {
log.warn("Cannot get an devices for HomeAssistant " + hassAddress.getName() + " as response is not parsable."); log.warn("Cannot get an devices for HomeAssistant " + hassAddress.getName()
} + " as response is not parsable.");
else { } else {
theDeviceStates = new ArrayList<State>(Arrays.asList(theHassStates)); theDeviceStates = new ArrayList<State>(Arrays.asList(theHassStates));
} }
} } else
else
log.warn("Cannot get an devices for HomeAssistant " + hassAddress.getName() + " http call failed."); log.warn("Cannot get an devices for HomeAssistant " + hassAddress.getName() + " http call failed.");
return theDeviceStates; return theDeviceStates;
} }
protected void closeClient() { protected void closeClient() {
anHttpHandler.closeHandler(); anHttpHandler.closeHandler();
anHttpHandler = null; anHttpHandler = null;
} }
private boolean isLegacyAuth() {
if (theAuthType == null) {
try {
theAuthType = new Gson().fromJson(hassAddress.getExtensions(), HassAuth.class);
} catch (Exception e) {
log.warn("Could not read hass auth - continuing with defaults.");
theAuthType = new HassAuth();
theAuthType.setLegacyauth(false);
}
}
return theAuthType.isLegacyauth();
}
private NameValue[] getAuthHeader() {
if (headers == null) {
if (hassAddress.getPassword() != null && !hassAddress.getPassword().isEmpty()) {
headers = new NameValue[1];
headers[0] = new NameValue();
if (isLegacyAuth()) {
headers[0].setName("x-ha-access");
headers[0].setValue(hassAddress.getPassword());
} else {
headers[0].setName("Authorization");
headers[0].setValue("Bearer " + hassAddress.getPassword());
}
}
} else if(hassAddress.getPassword() == null || hassAddress.getPassword().isEmpty()) {
headers = null;
}
return headers;
}
} }

View File

@@ -53,6 +53,16 @@ public class UpnpListener {
+ HueConstants.API_VERSION + "\r\n" + "NTS: ssdp:alive\r\n" + "hue-bridgeid: %s\r\n" + "NT: uuid:" + 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"; + HueConstants.UUID_PREFIX + "%s\r\n" + "USN: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n\r\n";
private String notifyTemplate2 = "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: upnp:rootdevice\r\n" + "USN: uuid:" + HueConstants.UUID_PREFIX + "%s::upnp:rootdevice\r\n\r\n";
private String notifyTemplate3 = "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: urn:schemas-upnp-org:device:basic:1\r\n" + "USN: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n\r\n";
public UpnpListener(BridgeSettingsDescriptor theSettings, BridgeControlDescriptor theControl, public UpnpListener(BridgeSettingsDescriptor theSettings, BridgeControlDescriptor theControl,
UDPDatagramSender aUdpDatagramSender) throws IOException { UDPDatagramSender aUdpDatagramSender) throws IOException {
super(); super();
@@ -242,9 +252,9 @@ public class UpnpListener {
discoveryResponse = String.format(responseTemplateOriginal, Configuration.UPNP_MULTICAST_ADDRESS, discoveryResponse = String.format(responseTemplateOriginal, Configuration.UPNP_MULTICAST_ADDRESS,
Configuration.UPNP_DISCOVERY_PORT, httpLocationAddress, httpServerPort, bridgeId, bridgeSNUUID); Configuration.UPNP_DISCOVERY_PORT, httpLocationAddress, httpServerPort, bridgeId, bridgeSNUUID);
if (traceupnp) { if (traceupnp) {
log.info("Traceupnp: send upnp discovery template Original with response address: " + httpLocationAddress + ":" log.info("Traceupnp: send upnp discovery template Original with response address: "
+ httpServerPort + " to address: " + requester + ":" + sourcePort); + httpLocationAddress + ":" + httpServerPort + " to address: " + requester + ":" + sourcePort);
} else }
log.debug("sendUpnpResponse to address: " + requester + ":" + sourcePort log.debug("sendUpnpResponse to address: " + requester + ":" + sourcePort
+ " with discovery responseTemplateOriginal is <<<" + discoveryResponse + ">>>"); + " with discovery responseTemplateOriginal is <<<" + discoveryResponse + ">>>");
sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort); sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort);
@@ -252,9 +262,9 @@ public class UpnpListener {
discoveryResponse = String.format(responseTemplateOriginal, Configuration.UPNP_MULTICAST_ADDRESS, discoveryResponse = String.format(responseTemplateOriginal, Configuration.UPNP_MULTICAST_ADDRESS,
Configuration.UPNP_DISCOVERY_PORT, httpLocationAddress, httpServerPort, bridgeId, bridgeSNUUID); Configuration.UPNP_DISCOVERY_PORT, httpLocationAddress, httpServerPort, bridgeId, bridgeSNUUID);
if (traceupnp) { if (traceupnp) {
log.info("Traceupnp: send upnp discovery template Original with response address: " + httpLocationAddress + ":" log.info("Traceupnp: send upnp discovery template Original with response address: "
+ httpServerPort + " to address: " + requester + ":" + sourcePort); + httpLocationAddress + ":" + httpServerPort + " to address: " + requester + ":" + sourcePort);
} else }
log.debug("sendUpnpResponse to address: " + requester + ":" + sourcePort log.debug("sendUpnpResponse to address: " + requester + ":" + sourcePort
+ " with discovery responseTemplateOriginal is <<<" + discoveryResponse + ">>>"); + " with discovery responseTemplateOriginal is <<<" + discoveryResponse + ">>>");
sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort); sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort);
@@ -268,7 +278,7 @@ public class UpnpListener {
if (traceupnp) { if (traceupnp) {
log.info("Traceupnp: send upnp discovery template 1 with response address: " + httpLocationAddress + ":" log.info("Traceupnp: send upnp discovery template 1 with response address: " + httpLocationAddress + ":"
+ httpServerPort + " to address: " + requester + ":" + sourcePort); + httpServerPort + " to address: " + requester + ":" + sourcePort);
} else }
log.debug("sendUpnpResponse to address: " + requester + ":" + sourcePort log.debug("sendUpnpResponse to address: " + requester + ":" + sourcePort
+ " with discovery responseTemplate1 is <<<" + discoveryResponse + ">>>"); + " with discovery responseTemplate1 is <<<" + discoveryResponse + ">>>");
sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort); sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort);
@@ -284,7 +294,7 @@ public class UpnpListener {
if (traceupnp) { if (traceupnp) {
log.info("Traceupnp: send upnp discovery template 2 with response address: " + httpLocationAddress + ":" log.info("Traceupnp: send upnp discovery template 2 with response address: " + httpLocationAddress + ":"
+ httpServerPort + " to address: " + requester + ":" + sourcePort); + httpServerPort + " to address: " + requester + ":" + sourcePort);
} else }
log.debug("sendUpnpResponse to address: " + requester + ":" + sourcePort log.debug("sendUpnpResponse to address: " + requester + ":" + sourcePort
+ " discovery responseTemplate2 is <<<" + discoveryResponse + ">>>"); + " discovery responseTemplate2 is <<<" + discoveryResponse + ">>>");
sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort); sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort);
@@ -299,7 +309,7 @@ public class UpnpListener {
if (traceupnp) { if (traceupnp) {
log.info("Traceupnp: send upnp discovery template 3 with response address: " + httpLocationAddress + ":" log.info("Traceupnp: send upnp discovery template 3 with response address: " + httpLocationAddress + ":"
+ httpServerPort + " to address: " + requester + ":" + sourcePort); + httpServerPort + " to address: " + requester + ":" + sourcePort);
} else }
log.debug("sendUpnpResponse to address: " + requester + ":" + sourcePort log.debug("sendUpnpResponse to address: " + requester + ":" + sourcePort
+ " discovery responseTemplate3 is <<<" + discoveryResponse + ">>>"); + " discovery responseTemplate3 is <<<" + discoveryResponse + ">>>");
sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort); sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort);
@@ -316,17 +326,50 @@ public class UpnpListener {
protected void sendUpnpNotify(InetAddress aSocketAddress) { protected void sendUpnpNotify(InetAddress aSocketAddress) {
String notifyData = null; String notifyData = null;
try {
Thread.sleep(theUpnpSendDelay);
} catch (InterruptedException e) {
// noop
}
notifyData = String.format(notifyTemplate, Configuration.UPNP_MULTICAST_ADDRESS, notifyData = String.format(notifyTemplate, Configuration.UPNP_MULTICAST_ADDRESS,
Configuration.UPNP_DISCOVERY_PORT, upnpConfigIP, httpServerPort, bridgeId, bridgeSNUUID, bridgeSNUUID); Configuration.UPNP_DISCOVERY_PORT, upnpConfigIP, httpServerPort, bridgeId, bridgeSNUUID, bridgeSNUUID);
log.debug("sendUpnpNotify notifyTemplate is <<<" + notifyData + ">>>"); sendNotifyDatagram(notifyData, aSocketAddress, "notifyTemplate1");
try {
Thread.sleep(theUpnpSendDelay);
} catch (InterruptedException e) {
// noop
}
notifyData = String.format(notifyTemplate2, Configuration.UPNP_MULTICAST_ADDRESS,
Configuration.UPNP_DISCOVERY_PORT, upnpConfigIP, httpServerPort, bridgeId, bridgeSNUUID);
sendNotifyDatagram(notifyData, aSocketAddress, "notifyTemplate2");
try {
Thread.sleep(theUpnpSendDelay);
} catch (InterruptedException e) {
// noop
}
notifyData = String.format(notifyTemplate3, Configuration.UPNP_MULTICAST_ADDRESS,
Configuration.UPNP_DISCOVERY_PORT, upnpConfigIP, httpServerPort, bridgeId, bridgeSNUUID);
sendNotifyDatagram(notifyData, aSocketAddress, "notifyTemplate3");
}
public void sendNotifyDatagram(String notifyData, InetAddress aSocketAddress, String templateNumber) {
if (traceupnp) {
log.info("Traceupnp: sendUpnpNotify {}", templateNumber);
}
log.debug("sendUpnpNotify {} is <<<{}>>>", templateNumber, notifyData);
DatagramPacket notifyPacket = new DatagramPacket(notifyData.getBytes(), notifyData.length(), aSocketAddress, DatagramPacket notifyPacket = new DatagramPacket(notifyData.getBytes(), notifyData.length(), aSocketAddress,
Configuration.UPNP_DISCOVERY_PORT); Configuration.UPNP_DISCOVERY_PORT);
try { try {
upnpMulticastSocket.send(notifyPacket); upnpMulticastSocket.send(notifyPacket);
} catch (IOException e1) { } catch (IOException e1) {
log.warn("UpnpListener encountered an error sending upnp notify packet. IP: " log.warn("UpnpListener encountered an error sending upnp {}. IP: {} with message: {}", templateNumber,
+ notifyPacket.getAddress().getHostAddress() + " with message: " + e1.getMessage()); notifyPacket.getAddress().getHostAddress(), e1.getMessage());
log.debug("UpnpListener send upnp notify exception: ", e1); log.debug("UpnpListener send {} exception: ", templateNumber, e1);
} }
} }

View File

@@ -29,7 +29,9 @@
.scrollArea { .scrollArea {
height: 100%; height: 100%;
/* THis makes the table scroll - disabled as a feature for now
max-height: 800px; max-height: 800px;
*/
overflow-x: auto; overflow-x: auto;
overflow-y: auto; overflow-y: auto;
border: 1px solid #d5d5d5; border: 1px solid #d5d5d5;

View File

@@ -17,6 +17,23 @@
<link href="css/strength-meter.min.css" rel="stylesheet"> <link href="css/strength-meter.min.css" rel="stylesheet">
<link href="css/colorpicker.min.css" rel="stylesheet"> <link href="css/colorpicker.min.css" rel="stylesheet">
<style id="compiled-css" type="text/css">
.goToTop
{
position: fixed;
width: 100px;
height: 40px;
bottom: 0;
right: 0;
z-index: 100000;
cursor: pointer;
margin: 10px;
-moz-opacity: 0.60;
opacity: .60;
filter: alpha(opacity=60);
}
</style>
<!--[if lt IE 9]> <!--[if lt IE 9]>
<script type="text/javascript" src="js/html5shiv.min.js"></script> <script type="text/javascript" src="js/html5shiv.min.js"></script>
<script type="text/javascript" src="js/respond.min.js"></script> <script type="text/javascript" src="js/respond.min.js"></script>
@@ -75,6 +92,10 @@
</div> </div>
<span class="goToTop">
<button type="button" class="btn btn-light"><i class="glyphicon glyphicon-chevron-up"></i> Back to Top</button>
</span>
<!-- <input type="button" class="goToTop" value="Back to Top" style="display:none;background-color:blue" /> -->
<script src="js/jquery-1.11.3.min.js"></script> <script src="js/jquery-1.11.3.min.js"></script>
<script src="js/angular.min.js"></script> <script src="js/angular.min.js"></script>
@@ -93,5 +114,35 @@
<script src="js/ng-file-upload-shim.min.js"></script> <script src="js/ng-file-upload-shim.min.js"></script>
<script src="js/ng-file-upload.min.js"></script> <script src="js/ng-file-upload.min.js"></script>
<script src="scripts/app.js"></script> <script src="scripts/app.js"></script>
<script type="text/javascript">
$(window).load(function(){
$(window).scroll(function () {
if ($(this).scrollTop() > 100) {
$('.goToTop').fadeIn();
} else {
$('.goToTop').fadeOut();
}
});
$('.goToTop').click(function () {
$("html, body").animate({ scrollTop: 0 }, 1000);
return false;
});
});
</script>
<script>
// tell the embed parent frame the height of the content
if (window.parent && window.parent.parent){
window.parent.parent.postMessage(["resultsFrame", {
height: document.body.getBoundingClientRect().height,
slug: "fvdrw83s"
}], "*")
}
// always overwrite window.name, in case users try to set it manually
window.name = "result"
</script>
</body> </body>
</html> </html>

View File

@@ -1875,7 +1875,7 @@ app.controller('SystemController', function ($scope, $location, bridgeService, n
} }
} }
}; };
$scope.addHasstoSettings = function (newhassname, newhassip, newhassport, newhasspassword, newhasssecure) { $scope.addHasstoSettings = function (newhassname, newhassip, newhassport, newhasspassword, newhasssecure, newhassauth) {
if ($scope.bridge.settings.hassaddress === undefined || $scope.bridge.settings.hassaddress === null) { if ($scope.bridge.settings.hassaddress === undefined || $scope.bridge.settings.hassaddress === null) {
$scope.bridge.settings.hassaddress = { $scope.bridge.settings.hassaddress = {
devices: [] devices: []
@@ -1886,7 +1886,8 @@ app.controller('SystemController', function ($scope, $location, bridgeService, n
ip: newhassip, ip: newhassip,
port: newhassport, port: newhassport,
password: newhasspassword, password: newhasspassword,
secure: newhasssecure secure: newhasssecure,
extensions: newhassauth
}; };
$scope.bridge.settings.hassaddress.devices.push(newhass); $scope.bridge.settings.hassaddress.devices.push(newhass);
$scope.newhassname = null; $scope.newhassname = null;

File diff suppressed because it is too large Load Diff