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> <groupId>com.bwssystems.HABridge</groupId>
<artifactId>ha-bridge</artifactId> <artifactId>ha-bridge</artifactId>
<version>3.1.0k</version> <version>3.1.0l</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>HA Bridge</name> <name>HA Bridge</name>

View File

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

View File

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

View File

@@ -24,75 +24,34 @@ public class UpnpListener {
private boolean strict; private boolean strict;
private boolean traceupnp; private boolean traceupnp;
private BridgeControlDescriptor bridgeControl; private BridgeControlDescriptor bridgeControl;
private boolean discoveryTemplateLatest; private String responseTemplate1 = "HTTP/1.1 200 OK\r\n" +
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" +
"HOST: %s:%s\r\n" + "HOST: %s:%s\r\n" +
"CACHE-CONTROL: max-age=100\r\n" + "CACHE-CONTROL: max-age=100\r\n" +
"EXT:\r\n" +
"LOCATION: http://%s:%s/description.xml\r\n" + "LOCATION: http://%s:%s/description.xml\r\n" +
"SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/1.14.0\r\n" + "SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/1.15.0\r\n" +
"NTS: ssdp:alive\r\n" +
"hue-bridgeid: %s\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" + "ST: upnp:rootdevice\r\n" +
"USN: uuid:2f402f80-da50-11e1-9b23-001788102201\r\n\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" +
/*
private String discoveryTemplate = "HTTP/1.1 200 OK\r\n" +
"HOST: %s:%s\r\n" + "HOST: %s:%s\r\n" +
"CACHE-CONTROL: max-age=86400\r\n" + "CACHE-CONTROL: max-age=100\r\n" +
"EXT:\r\n" + "EXT:\r\n" +
"LOCATION: http://%s:%s/description.xml\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" + "hue-bridgeid: %s\r\n" +
"ST: upnp:rootdevice\r\n" + "ST: uuid:2f402f80-da50-11e1-9b23-%s\r\n" +
"USN: uuid:2f402f80-da50-11e1-9b23-001788102201\r\n\r\n"; "USN: uuid:2f402f80-da50-11e1-9b23-%s\r\n\r\n";
private String responseTemplate3 = "HTTP/1.1 200 OK\r\n" +
discoveryResponse = String.format(discoveryTemplate, Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT, responseAddress, httpServerPort, HuePublicConfig.createConfig("temp", responseAddress).getBridgeid()); "HOST: %s:%s\r\n" +
*/ "CACHE-CONTROL: max-age=100\r\n" +
private String discoveryTemplate091516 = "HTTP/1.1 200 OK\r\n" +
"CACHE-CONTROL: max-age=86400\r\n" +
"EXT:\r\n" + "EXT:\r\n" +
"LOCATION: http://%s:%s/description.xml\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" + "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"; "USN: uuid:2f402f80-da50-11e1-9b23-%s\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";
*/
public UpnpListener(BridgeSettingsDescriptor theSettings, BridgeControlDescriptor theControl, UDPDatagramSender aUdpDatagramSender) { public UpnpListener(BridgeSettingsDescriptor theSettings, BridgeControlDescriptor theControl, UDPDatagramSender aUdpDatagramSender) {
super(); super();
theUDPDatagramSender = aUdpDatagramSender; theUDPDatagramSender = aUdpDatagramSender;
@@ -101,7 +60,6 @@ public class UpnpListener {
strict = theSettings.isUpnpStrict(); strict = theSettings.isUpnpStrict();
traceupnp = theSettings.isTraceupnp(); traceupnp = theSettings.isTraceupnp();
bridgeControl = theControl; bridgeControl = theControl;
discoveryTemplateLatest = true;
} }
@SuppressWarnings("resource") @SuppressWarnings("resource")
@@ -243,19 +201,33 @@ public class UpnpListener {
protected void sendUpnpResponse(InetAddress requester, int sourcePort) throws IOException { protected void sendUpnpResponse(InetAddress requester, int sourcePort) throws IOException {
String discoveryResponse = null; String discoveryResponse = null;
String bridgeIdMac = null; String bridgeId = null;
if(discoveryTemplateLatest) { String bridgeSNUUID = null;
bridgeIdMac = HuePublicConfig.createConfig("temp", responseAddress).getBridgeid(); HuePublicConfig aHueConfig = HuePublicConfig.createConfig("temp", responseAddress);
discoveryResponse = String.format(discoveryTemplate, responseAddress, httpServerPort, bridgeIdMac); bridgeId = aHueConfig.getBridgeid();
} bridgeSNUUID = aHueConfig.getSNUUIDFromMac();
else discoveryResponse = String.format(responseTemplate1, Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT, responseAddress, httpServerPort, bridgeId, bridgeSNUUID);
discoveryResponse = String.format(discoveryTemplate091516, responseAddress, httpServerPort);
if(traceupnp) { if(traceupnp) {
log.info("Traceupnp: sendUpnpResponse discovery template with address: " + responseAddress + " and port: " + httpServerPort); log.info("Traceupnp: sendUpnpResponse discovery responseTemplate1 is <<<" + discoveryResponse + ">>>");
log.info("Traceupnp: discoveryResponse is <<<" + discoveryResponse + ">>>");
} }
else 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); 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()); log.debug("upnp device settings requested: " + " from " + request.ip() + ":" + request.port());
String portNumber = Integer.toString(request.port()); String portNumber = Integer.toString(request.port());
String filledTemplate = null; 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); filledTemplate = String.format(hueTemplate, theSettings.getUpnpConfigAddress(), portNumber, theSettings.getUpnpConfigAddress(), bridgeIdMac, bridgeIdMac);
if(theSettings.isTraceupnp()) if(theSettings.isTraceupnp())
log.info("Traceupnp: upnp device settings template filled with address: " + theSettings.getUpnpConfigAddress() + " and port: " + portNumber); 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);
}
}