diff --git a/pom.xml b/pom.xml index c20860c..8cf2371 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.bwssystems.HABridge ha-bridge - 3.1.0j + 3.1.0k jar HA Bridge diff --git a/src/main/java/com/bwssystems/HABridge/HABridge.java b/src/main/java/com/bwssystems/HABridge/HABridge.java index 928570c..ae4ab4f 100644 --- a/src/main/java/com/bwssystems/HABridge/HABridge.java +++ b/src/main/java/com/bwssystems/HABridge/HABridge.java @@ -13,6 +13,7 @@ import com.bwssystems.NestBridge.NestHome; import com.bwssystems.hal.HalHome; import com.bwssystems.harmony.HarmonyHome; import com.bwssystems.hue.HueHome; +import com.bwssystems.util.UDPDatagramSender; public class HABridge { @@ -39,6 +40,7 @@ public class HABridge { HueHome hueHome; HalHome halHome; HueMulator theHueMulator; + UDPDatagramSender udpSender; UpnpSettingsResource theSettingResponder; UpnpListener theUpnpListener; SystemControl theSystem; @@ -72,29 +74,37 @@ public class HABridge { halHome = new HalHome(bridgeSettings.getBridgeSettingsDescriptor()); // setup the class to handle the resource setup rest api theResources = new DeviceResource(bridgeSettings.getBridgeSettingsDescriptor(), harmonyHome, nestHome, hueHome, halHome); - // setup the class to handle the hue emulator rest api - theHueMulator = new HueMulator(bridgeSettings.getBridgeSettingsDescriptor(), theResources.getDeviceRepository(), harmonyHome, nestHome, hueHome); - theHueMulator.setupServer(); // setup the class to handle the upnp response rest api theSettingResponder = new UpnpSettingsResource(bridgeSettings.getBridgeSettingsDescriptor()); theSettingResponder.setupServer(); - // wait for the sparkjava initialization of the rest api classes to be complete - awaitInitialization(); - - // start the upnp ssdp discovery listener - theUpnpListener = new UpnpListener(bridgeSettings.getBridgeSettingsDescriptor(), bridgeSettings.getBridgeControl()); - if(theUpnpListener.startListening()) - log.info("HA Bridge (v" + theVersion.getVersion() + ") reinitialization requessted...."); - else - bridgeSettings.getBridgeControl().setStop(true); - if(bridgeSettings.getBridgeSettingsDescriptor().isSettingsChanged()) - bridgeSettings.save(bridgeSettings.getBridgeSettingsDescriptor()); + // setup the UDP Datagram socket to be used by the HueMulator and the upnpListener + udpSender = UDPDatagramSender.createUDPDatagramSender(bridgeSettings.getBridgeSettingsDescriptor().getUpnpResponsePort()); + if(udpSender == null) { + bridgeSettings.getBridgeControl().setStop(true); + } + else { + // setup the class to handle the hue emulator rest api + theHueMulator = new HueMulator(bridgeSettings.getBridgeSettingsDescriptor(), theResources.getDeviceRepository(), harmonyHome, nestHome, hueHome, udpSender); + theHueMulator.setupServer(); + // wait for the sparkjava initialization of the rest api classes to be complete + awaitInitialization(); + + // start the upnp ssdp discovery listener + theUpnpListener = new UpnpListener(bridgeSettings.getBridgeSettingsDescriptor(), bridgeSettings.getBridgeControl(), udpSender); + if(theUpnpListener.startListening()) + log.info("HA Bridge (v" + theVersion.getVersion() + ") reinitialization requessted...."); + else + bridgeSettings.getBridgeControl().setStop(true); + if(bridgeSettings.getBridgeSettingsDescriptor().isSettingsChanged()) + bridgeSettings.save(bridgeSettings.getBridgeSettingsDescriptor()); + } bridgeSettings.getBridgeControl().setReinit(false); stop(); nestHome.closeTheNest(); nestHome = null; harmonyHome.shutdownHarmonyHubs(); harmonyHome = null; + udpSender.closeResponseSocket(); } log.info("HA Bridge (v" + theVersion.getVersion() + ") exiting...."); System.exit(0); diff --git a/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java b/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java index a93d7d5..60bca51 100644 --- a/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java +++ b/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java @@ -27,6 +27,7 @@ import com.bwssystems.hue.HueHome; import com.bwssystems.hue.HueUtil; import com.bwssystems.nest.controller.Nest; import com.bwssystems.util.JsonTransformer; +import com.bwssystems.util.UDPDatagramSender; import com.google.gson.Gson; import net.java.dev.eval.Expression; @@ -60,8 +61,6 @@ import java.io.DataOutputStream; import java.io.IOException; import java.math.BigDecimal; import java.math.BigInteger; -import java.net.DatagramPacket; -import java.net.DatagramSocket; import java.net.InetAddress; import java.net.Socket; import java.nio.charset.Charset; @@ -99,12 +98,13 @@ public class HueMulator implements HueErrorStringSet { private SSLConnectionSocketFactory sslsf; private RequestConfig globalConfig; private BridgeSettingsDescriptor bridgeSettings; + private UDPDatagramSender theUDPDatagramSender; private byte[] sendData; private String hueUser; private String errorString; - public HueMulator(BridgeSettingsDescriptor theBridgeSettings, DeviceRepository aDeviceRepository, HarmonyHome theHarmonyHome, NestHome aNestHome, HueHome aHueHome){ + public HueMulator(BridgeSettingsDescriptor theBridgeSettings, DeviceRepository aDeviceRepository, HarmonyHome theHarmonyHome, NestHome aNestHome, HueHome aHueHome, UDPDatagramSender aUdpDatagramSender) { httpClient = HttpClients.createDefault(); // Trust own CA and all self-signed certs sslcontext = SSLContexts.createDefault(); @@ -136,6 +136,7 @@ public class HueMulator implements HueErrorStringSet { else this.myHueHome = null; bridgeSettings = theBridgeSettings; + theUDPDatagramSender = aUdpDatagramSender; hueUser = null; errorString = null; } @@ -905,10 +906,7 @@ public class HueMulator implements HueErrorStringSet { } if(callItems[i].getItem().contains("udp://")) { log.debug("executing HUE api request to UDP: " + callItems[i].getItem()); - DatagramSocket responseSocket = new DatagramSocket(Integer.parseInt(port)); - DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, Integer.parseInt(port)); - responseSocket.send(sendPacket); - responseSocket.close(); + theUDPDatagramSender.sendUDPResponse(new String(sendData), IPAddress, Integer.parseInt(port)); } else if(callItems[i].getItem().contains("tcp://")) { diff --git a/src/main/java/com/bwssystems/HABridge/upnp/UpnpListener.java b/src/main/java/com/bwssystems/HABridge/upnp/UpnpListener.java index 3ed7b79..dba4225 100644 --- a/src/main/java/com/bwssystems/HABridge/upnp/UpnpListener.java +++ b/src/main/java/com/bwssystems/HABridge/upnp/UpnpListener.java @@ -7,6 +7,7 @@ import com.bwssystems.HABridge.BridgeControlDescriptor; import com.bwssystems.HABridge.BridgeSettingsDescriptor; import com.bwssystems.HABridge.Configuration; import com.bwssystems.HABridge.api.hue.HuePublicConfig; +import com.bwssystems.util.UDPDatagramSender; import java.io.IOException; import java.net.*; @@ -17,7 +18,7 @@ import org.apache.http.conn.util.*; public class UpnpListener { private Logger log = LoggerFactory.getLogger(UpnpListener.class); - private int upnpResponsePort; + private UDPDatagramSender theUDPDatagramSender; private int httpServerPort; private String responseAddress; private boolean strict; @@ -92,9 +93,9 @@ public class UpnpListener { "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) { + public UpnpListener(BridgeSettingsDescriptor theSettings, BridgeControlDescriptor theControl, UDPDatagramSender aUdpDatagramSender) { super(); - upnpResponsePort = theSettings.getUpnpResponsePort(); + theUDPDatagramSender = aUdpDatagramSender; httpServerPort = Integer.valueOf(theSettings.getServerPort()); responseAddress = theSettings.getUpnpConfigAddress(); strict = theSettings.isUpnpStrict(); @@ -106,33 +107,9 @@ public class UpnpListener { @SuppressWarnings("resource") public boolean startListening(){ log.info("UPNP Discovery Listener starting...."); - DatagramSocket responseSocket = null; MulticastSocket upnpMulticastSocket = null; Enumeration ifs = null; - boolean portLoopControl = true; - int retryCount = 0; - while(portLoopControl) { - try { - responseSocket = new DatagramSocket(upnpResponsePort); - if(retryCount > 0) - log.info("Upnp Response Port issue, found open port: " + upnpResponsePort); - portLoopControl = false; - } catch(SocketException e) { - if(retryCount == 0) - log.warn("Upnp Response Port is in use, starting loop to find open port for 20 tries - configured port is: " + upnpResponsePort); - if(retryCount >= 20) { - portLoopControl = false; - log.error("Upnp Response Port issue, could not find open port - last port tried: " + upnpResponsePort + " with message: " + e.getMessage()); - return false; - } - } - if(portLoopControl) { - retryCount++; - upnpResponsePort++; - } - } - try { upnpMulticastSocket = new MulticastSocket(Configuration.UPNP_DISCOVERY_PORT); } catch(IOException e){ @@ -189,7 +166,7 @@ public class UpnpListener { upnpMulticastSocket.receive(packet); if (isSSDPDiscovery(packet)) { try { - sendUpnpResponse(responseSocket, packet.getAddress(), packet.getPort()); + sendUpnpResponse(packet.getAddress(), packet.getPort()); } catch (IOException e) { if(e.getMessage().equalsIgnoreCase("Host is down")) log.warn("UpnpListener encountered an error sending upnp response packet as requesting host is now not available. IP: " + packet.getAddress().getHostAddress()); @@ -213,7 +190,6 @@ public class UpnpListener { } } upnpMulticastSocket.close(); - responseSocket.close(); if (bridgeControl.isReinit()) log.info("UPNP Discovery Listener - ended, restart found"); if (bridgeControl.isStop()) @@ -265,7 +241,7 @@ public class UpnpListener { return false; } - protected void sendUpnpResponse(DatagramSocket socket, InetAddress requester, int sourcePort) throws IOException { + protected void sendUpnpResponse(InetAddress requester, int sourcePort) throws IOException { String discoveryResponse = null; String bridgeIdMac = null; if(discoveryTemplateLatest) { @@ -280,7 +256,6 @@ public class UpnpListener { } else log.debug("sendUpnpResponse discovery template with address: " + responseAddress + " and port: " + httpServerPort); - DatagramPacket response = new DatagramPacket(discoveryResponse.getBytes(), discoveryResponse.length(), requester, sourcePort); - socket.send(response); + theUDPDatagramSender.sendUDPResponse(discoveryResponse, requester, sourcePort); } }