I got some more info from another source about the discovery responses

of a real hue. It sends three responses not just one. Also I have
updated the S/N UUID and the Hue Bridge ID creation as they are
different.
This commit is contained in:
Admin
2016-10-10 13:23:29 -05:00
parent 004276d3ea
commit 23d43b0136
6 changed files with 133 additions and 93 deletions

View File

@@ -5,7 +5,7 @@
<groupId>com.bwssystems.HABridge</groupId>
<artifactId>ha-bridge</artifactId>
<version>3.1.0k</version>
<version>3.1.0l</version>
<packaging>jar</packaging>
<name>HA Bridge</name>

View File

@@ -40,10 +40,10 @@ public class HueConfig
SimpleDateFormat dateFormatGmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
dateFormatGmt.setTimeZone(TimeZone.getTimeZone("UTC"));
aConfig.setMac(HueConfig.getMacAddress(ipaddress));
aConfig.setApiversion("1.14.0");
aConfig.setApiversion("1.15.0");
aConfig.setPortalservices(false);
aConfig.setGateway(ipaddress);
aConfig.setSwversion("01033989");
aConfig.setSwversion("01035934");
aConfig.setLinkbutton(true);
aConfig.setIpaddress(ipaddress);
aConfig.setProxyport(0);
@@ -56,7 +56,7 @@ public class HueConfig
aConfig.setLocaltime(dateFormat.format(new Date()));
aConfig.setTimezone(TimeZone.getDefault().getID());
aConfig.setZigbeechannel("6");
aConfig.setBridgeid(HuePublicConfig.getBridgeIdFromMac(aConfig.getMac(), ipaddress));
aConfig.setBridgeid(HuePublicConfig.createConfig(name, ipaddress).getHueBridgeIdFromMac());
aConfig.setModelid("BSB002");
aConfig.setFactorynew(false);
aConfig.setReplacesbridgeid(null);

View File

@@ -1,13 +1,11 @@
package com.bwssystems.HABridge.api.hue;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.StringTokenizer;
import javax.xml.bind.DatatypeConverter;
public class HuePublicConfig
{
@@ -23,10 +21,10 @@ public class HuePublicConfig
public static HuePublicConfig createConfig(String name, String ipaddress) {
HuePublicConfig aConfig = new HuePublicConfig();
aConfig.setMac(HuePublicConfig.getMacAddress(ipaddress));
aConfig.setApiversion("1.14.0");
aConfig.setSwversion("01033989");
aConfig.setApiversion("1.15.0");
aConfig.setSwversion("01035934");
aConfig.setName(name);
aConfig.setBridgeid(HuePublicConfig.getBridgeIdFromMac(aConfig.getMac(), ipaddress));
aConfig.setBridgeid(aConfig.getHueBridgeIdFromMac());
aConfig.setModelid("BSB002");
aConfig.setFactorynew(false);
aConfig.setReplacesbridgeid(null);
@@ -67,24 +65,22 @@ public class HuePublicConfig
return sb.toString();
}
protected static String getBridgeIdFromMac(String macAddr, String ipAddr)
public String getSNUUIDFromMac()
{
StringTokenizer st = new StringTokenizer(macAddr, ":");
String bridgeId = "";
// String port = null;
StringTokenizer st = new StringTokenizer(this.getMac(), ":");
String bridgeUUID = "";
while(st.hasMoreTokens()) {
bridgeId = bridgeId + st.nextToken();
bridgeUUID = bridgeUUID + st.nextToken();
}
// if(ipAddr.contains(":")) {
// port = ipAddr.substring(ipAddr.indexOf(":"));
// BigInteger bigInt = BigInteger.valueOf(Integer.getInteger(port).intValue());
// byte[] theBytes = bigInt.toByteArray();
// bridgeId = bridgeId + DatatypeConverter.printHexBinary(theBytes);
// }
// else
// bridgeId = bridgeId + "0800";
bridgeId = bridgeId.toLowerCase();
return bridgeId;
bridgeUUID = bridgeUUID.toLowerCase();
return bridgeUUID.toLowerCase();
}
protected String getHueBridgeIdFromMac()
{
String cleanMac = this.getSNUUIDFromMac();
String bridgeId = cleanMac.substring(0, 6) + "FFFE" + cleanMac.substring(6);
return bridgeId.toUpperCase();
}
public String getMac() {

View File

@@ -24,75 +24,34 @@ public class UpnpListener {
private boolean strict;
private boolean traceupnp;
private BridgeControlDescriptor bridgeControl;
private boolean discoveryTemplateLatest;
private String discoveryTemplate = "HTTP/1.1 200 OK\r\n" +
"CACHE-CONTROL: max-age=86400\r\n" +
"EXT:\r\n" +
"LOCATION: http://%s:%s/description.xml\r\n" +
"SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/1.14.0\r\n" +
"ST: urn:schemas-upnp-org:device:basic:1\r\n" +
"USN: uuid:2f402f80-da50-11e1-9b23-%s\r\n\r\n";
/*
private String discoveryTemplate = "NOTIFY * HTTP/1.1\r\n" +
private String responseTemplate1 = "HTTP/1.1 200 OK\r\n" +
"HOST: %s:%s\r\n" +
"CACHE-CONTROL: max-age=100\r\n" +
"EXT:\r\n" +
"LOCATION: http://%s:%s/description.xml\r\n" +
"SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/1.14.0\r\n" +
"NTS: ssdp:alive\r\n" +
"SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/1.15.0\r\n" +
"hue-bridgeid: %s\r\n" +
"NT: uuid:2f402f80-da50-11e1-9b23-%s\r\n" +
"USN: uuid:2f402f80-da50-11e1-9b23-%s\r\n\r\n";
discoveryResponse = String.format(discoveryTemplate, Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT, responseAddress, httpServerPort, bridgeIdMac, bridgeIdMac, bridgeIdMac);
*/
/*
private String discoveryTemplate = "HTTP/1.1 200 OK\r\n" +
"CACHE-CONTROL: max-age=86400\r\n" +
"EXT:\r\n" +
"LOCATION: http://%s:%s/description.xml\r\n" +
"SERVER: FreeRTOS/7.4.2 UPnP/1.0 IpBridge/1.10.0\r\n" +
"ST: urn:schemas-upnp-org:device:basic:1\r\n" +
"USN: uuid:2f402f80-da50-11e1-9b23-001788102201::urn:schemas-upnp-org:device:basic:1\r\n\r\n";
discoveryResponse = String.format(discoveryTemplate, responseAddress, httpServerPort);
*/
/*
private String discoveryTemplate = "HTTP/1.1 200 OK\r\n" +
"CACHE-CONTROL: max-age=86400\r\n" +
"EXT:\r\n" +
"LOCATION: http://%s:%s/description.xml\r\n" +
"SERVER: FreeRTOS/7.4.2 UPnP/1.0 IpBridge/1.10.0\r\n" +
"ST: upnp:rootdevice\r\n" +
"USN: uuid:2f402f80-da50-11e1-9b23-001788102201\r\n\r\n";
*/
/*
private String discoveryTemplate = "HTTP/1.1 200 OK\r\n" +
"USN: uuid:2f402f80-da50-11e1-9b23-%s::upnp:rootdevice\r\n\r\n";
private String responseTemplate2 = "HTTP/1.1 200 OK\r\n" +
"HOST: %s:%s\r\n" +
"CACHE-CONTROL: max-age=86400\r\n" +
"CACHE-CONTROL: max-age=100\r\n" +
"EXT:\r\n" +
"LOCATION: http://%s:%s/description.xml\r\n" +
"SERVER: FreeRTOS/7.4.2 UPnP/1.0 IpBridge/1.10.0\r\n" +
"SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/1.15.0\r\n" +
"hue-bridgeid: %s\r\n" +
"ST: upnp:rootdevice\r\n" +
"USN: uuid:2f402f80-da50-11e1-9b23-001788102201\r\n\r\n";
discoveryResponse = String.format(discoveryTemplate, Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT, responseAddress, httpServerPort, HuePublicConfig.createConfig("temp", responseAddress).getBridgeid());
*/
private String discoveryTemplate091516 = "HTTP/1.1 200 OK\r\n" +
"CACHE-CONTROL: max-age=86400\r\n" +
"ST: uuid:2f402f80-da50-11e1-9b23-%s\r\n" +
"USN: uuid:2f402f80-da50-11e1-9b23-%s\r\n\r\n";
private String responseTemplate3 = "HTTP/1.1 200 OK\r\n" +
"HOST: %s:%s\r\n" +
"CACHE-CONTROL: max-age=100\r\n" +
"EXT:\r\n" +
"LOCATION: http://%s:%s/description.xml\r\n" +
"SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/1.10.0\r\n" +
"SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/1.15.0\r\n" +
"hue-bridgeid: %s\r\n" +
"ST: urn:schemas-upnp-org:device:basic:1\r\n" +
"USN: uuid:Socket-1_0-221438K0100073::urn:schemas-upnp-org:device:basic:1\r\n\r\n";
/*
private String discoveryTemplateOld = "HTTP/1.1 200 OK\r\n" +
"CACHE-CONTROL: max-age=86400\r\n" +
"EXT:\r\n" +
"LOCATION: http://%s:%s/upnp/amazon-ha-bridge/setup.xml\r\n" +
"OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" +
"01-NLS: %s\r\n" +
"ST: urn:schemas-upnp-org:device:basic:1\r\n" +
"USN: uuid:Socket-1_0-221438K0100073::urn:Belkin:device:**\r\n\r\n";
*/
"USN: uuid:2f402f80-da50-11e1-9b23-%s\r\n\r\n";
public UpnpListener(BridgeSettingsDescriptor theSettings, BridgeControlDescriptor theControl, UDPDatagramSender aUdpDatagramSender) {
super();
theUDPDatagramSender = aUdpDatagramSender;
@@ -101,7 +60,6 @@ public class UpnpListener {
strict = theSettings.isUpnpStrict();
traceupnp = theSettings.isTraceupnp();
bridgeControl = theControl;
discoveryTemplateLatest = true;
}
@SuppressWarnings("resource")
@@ -243,19 +201,33 @@ public class UpnpListener {
protected void sendUpnpResponse(InetAddress requester, int sourcePort) throws IOException {
String discoveryResponse = null;
String bridgeIdMac = null;
if(discoveryTemplateLatest) {
bridgeIdMac = HuePublicConfig.createConfig("temp", responseAddress).getBridgeid();
discoveryResponse = String.format(discoveryTemplate, responseAddress, httpServerPort, bridgeIdMac);
}
else
discoveryResponse = String.format(discoveryTemplate091516, responseAddress, httpServerPort);
String bridgeId = null;
String bridgeSNUUID = null;
HuePublicConfig aHueConfig = HuePublicConfig.createConfig("temp", responseAddress);
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 template with address: " + responseAddress + " and port: " + httpServerPort);
log.info("Traceupnp: discoveryResponse is <<<" + discoveryResponse + ">>>");
log.info("Traceupnp: sendUpnpResponse discovery responseTemplate1 is <<<" + discoveryResponse + ">>>");
}
else
log.debug("sendUpnpResponse discovery template with address: " + responseAddress + " and port: " + httpServerPort);
log.debug("sendUpnpResponse discovery responseTemplate1 is <<<" + discoveryResponse + ">>>");
theUDPDatagramSender.sendUDPResponse(discoveryResponse, requester, sourcePort);
discoveryResponse = String.format(responseTemplate2, Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT, responseAddress, httpServerPort, bridgeId, bridgeSNUUID, bridgeSNUUID);
if(traceupnp) {
log.info("Traceupnp: sendUpnpResponse discovery responseTemplate2 is <<<" + discoveryResponse + ">>>");
}
else
log.debug("sendUpnpResponse discovery responseTemplate2 is <<<" + discoveryResponse + ">>>");
theUDPDatagramSender.sendUDPResponse(discoveryResponse, requester, sourcePort);
discoveryResponse = String.format(responseTemplate3, Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT, responseAddress, httpServerPort, bridgeId, bridgeSNUUID);
if(traceupnp) {
log.info("Traceupnp: sendUpnpResponse discovery responseTemplate3 is <<<" + discoveryResponse + ">>>");
}
else
log.debug("sendUpnpResponse discovery responseTemplate3 is <<<" + discoveryResponse + ">>>");
theUDPDatagramSender.sendUDPResponse(discoveryResponse, requester, sourcePort);
}
}

View File

@@ -78,7 +78,7 @@ public class UpnpSettingsResource {
log.debug("upnp device settings requested: " + " from " + request.ip() + ":" + request.port());
String portNumber = Integer.toString(request.port());
String filledTemplate = null;
String bridgeIdMac = HuePublicConfig.createConfig("temp", theSettings.getUpnpConfigAddress()).getBridgeid();
String bridgeIdMac = HuePublicConfig.createConfig("temp", theSettings.getUpnpConfigAddress()).getSNUUIDFromMac();
filledTemplate = String.format(hueTemplate, theSettings.getUpnpConfigAddress(), portNumber, theSettings.getUpnpConfigAddress(), bridgeIdMac, bridgeIdMac);
if(theSettings.isTraceupnp())
log.info("Traceupnp: upnp device settings template filled with address: " + theSettings.getUpnpConfigAddress() + " and port: " + portNumber);

View File

@@ -0,0 +1,72 @@
package com.bwssystems.util;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class UDPDatagramSender {
private Logger log = LoggerFactory.getLogger(UDPDatagramSender.class);
private DatagramSocket responseSocket = null;
private int udpResponsePort;
public UDPDatagramSender() {
super();
udpResponsePort = 0;
}
public static UDPDatagramSender createUDPDatagramSender(int udpResponsePort) {
UDPDatagramSender aDatagramSender = new UDPDatagramSender();
if(aDatagramSender.initializeSocket(udpResponsePort))
return aDatagramSender;
else
return null;
}
private boolean initializeSocket(int port) {
log.info("Initializing UDP response Seocket...");
udpResponsePort = port;
boolean portLoopControl = true;
int retryCount = 0;
while(portLoopControl) {
try {
responseSocket = new DatagramSocket(udpResponsePort);
portLoopControl = false;
} catch(SocketException e) {
if(retryCount == 0)
log.warn("UDP Response Port is in use, starting loop to find open port for 20 tries - configured port is: " + udpResponsePort);
if(retryCount >= 20) {
portLoopControl = false;
log.error("UDP Response Port issue, could not find open port - last port tried: " + udpResponsePort + " with message: " + e.getMessage());
return false;
}
}
if(portLoopControl) {
retryCount++;
udpResponsePort++;
}
}
log.info("UDP response Seocket initialized to: " + udpResponsePort);
return true;
}
public int getUdpResponsePort() {
return udpResponsePort;
}
public void closeResponseSocket() {
responseSocket.close();
}
public void sendUDPResponse(String udpResponse, InetAddress requester, int sourcePort) throws IOException {
log.debug("Sending response string: <<<" + udpResponse + ">>>");
if(responseSocket == null)
throw new IOException("Socket not initialized");
DatagramPacket response = new DatagramPacket(udpResponse.getBytes(), udpResponse.length(), requester, sourcePort);
responseSocket.send(response);
}
}