rewrite for openhab 2.5
M pom.xml +9 -160
@@ 1,166 1,15 @@ 
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
-		 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-
-	<modelVersion>4.0.0</modelVersion>
-    <dependencies>
-        <dependency>
-            <groupId>org.eclipse.smarthome.config</groupId>
-            <artifactId>org.eclipse.smarthome.config.discovery.mdns</artifactId>
-            <version>0.9.0-SNAPSHOT</version>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.paho</groupId>
-            <artifactId>org.eclipse.paho.client.mqttv3</artifactId>
-            <version>1.0.2</version>
-        </dependency>
-    </dependencies>
-
-<parent>
-        <groupId>org.openhab</groupId>
-        <artifactId>pom-tycho</artifactId>
-        <version>2.4.0-SNAPSHOT</version>
-        <relativePath/>
-    </parent>
-
-        <properties>
-                <report.fail.on.error>false</report.fail.on.error>
-        <ohc.version>2.4.0-SNAPSHOT</ohc.version>
-    </properties>
-
-        <artifactId>org.openhab.binding.lutronmqtt</artifactId>
-
-        <name>LutronMQTT Binding</name>
-	<packaging>eclipse-plugin</packaging>
+<?xml version="1.0" encoding="UTF-8" standalone="no"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 
-    <build>
-        <testSourceDirectory>src/test</testSourceDirectory>
-        
-        <plugins>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-surefire-plugin</artifactId>
-                <version>2.19.1</version>
-                <executions>
-                    <execution>
-                        <id>test</id>
-                        <phase>test</phase>
-                        <configuration>
-                            <includes>
-                                <include>**/*Test.java</include>
-                            </includes>
-                        </configuration>
-                        <goals>
-                            <goal>test</goal>
-                        </goals>
-                    </execution>
-                </executions>
-            </plugin>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-compiler-plugin</artifactId>
-                <version>3.5.1</version>
-                <configuration>
-                    <source>1.7</source>
-                    <target>1.7</target>
-                </configuration>
-                <executions>
-                    <execution>
-                        <id>compiletests</id>
-                        <phase>test-compile</phase>
-                        <goals>
-                            <goal>testCompile</goal>
-                        </goals>
-                    </execution>
-                </executions>
-            </plugin>
-        </plugins>
-    </build>
+  <modelVersion>4.0.0</modelVersion>
 
-    <pluginRepositories>
-         <pluginRepository>
-               <id>jcenter</id>
-               <name>JCenter Repository</name>
-               <url>https://jcenter.bintray.com/</url>
-               <releases>
-                   <enabled>true</enabled>
-                   <updatePolicy>never</updatePolicy>
-               </releases>
-               <snapshots>
-                   <enabled>false</enabled>
-               </snapshots>
-         </pluginRepository>
-         <pluginRepository>
-             <id>artifactory</id>
-             <name>JFrog Artifactory Repository</name>
-             <url>https://openhab.jfrog.io/openhab/libs-release</url>
-             <releases>
-                 <enabled>true</enabled>
-                 <updatePolicy>never</updatePolicy>
-             </releases>
-             <snapshots>
-                 <enabled>false</enabled>
-             </snapshots>
-         </pluginRepository>
-       </pluginRepositories>
-
-	   <repositories>
-        
-	        <!-- releases -->
-	        <repository>
-	            <id>jcenter</id>
-	            <name>JCenter Repository</name>
-	            <url>https://jcenter.bintray.com/</url>
-	            <releases>
-	                <enabled>true</enabled>
-	                <updatePolicy>never</updatePolicy>
-	            </releases>
-	            <snapshots>
-	                <enabled>false</enabled>
-	            </snapshots>
-	        </repository>
+  <parent>
+    <groupId>org.openhab.addons.bundles</groupId>
+    <artifactId>org.openhab.addons.reactor.bundles</artifactId>
+    <version>2.5.3-SNAPSHOT</version>
+  </parent>
 
-	        <repository>
-	            <id>openhab-artifactory-release</id>
-	            <name>JFrog Artifactory Repository</name>
-	            <url>https://openhab.jfrog.io/openhab/libs-release</url>
-	            <releases>
-	                <enabled>true</enabled>
-	                <updatePolicy>never</updatePolicy>
-	            </releases>
-	            <snapshots>
-	                <enabled>false</enabled>
-	            </snapshots>
-	        </repository>
+  <artifactId>org.openhab.binding.lutron-mqtt</artifactId>
 
-	        <!-- snapshots -->
-	        <repository>
-	            <id>openhab-artifactory-snapshot</id>
-	            <name>JFrog Artifactory Repository</name>
-	            <url>https://openhab.jfrog.io/openhab/libs-snapshot</url>
-	            <releases>
-	                <enabled>false</enabled>
-	            </releases>
-	            <snapshots>
-	                <enabled>true</enabled>
-	                <updatePolicy>always</updatePolicy>
-	            </snapshots>
-	        </repository>
-
-	        <!-- SmartHome p2 repository -->
-	        <repository>
-	            <id>p2-smarthome</id>
-	            <url>https://openhab.jfrog.io/openhab/eclipse-smarthome-stable</url>
-	            <layout>p2</layout>
-	        </repository>
-
-	        <!-- openHAB dependencies p2 repository -->
-	        <repository>
-	            <id>p2-openhab-deps-repo</id>
-	            <url>https://dl.bintray.com/openhab/p2/openhab-deps-repo/${ohdr.version}</url>
-	            <layout>p2</layout>
-	        </repository>
-
-	    </repositories>
+  <name>openHAB Add-ons :: Bundles :: Lutron-MQTT Binding</name>
 
 </project>

          
A => src/main/history/dependencies.xml +4 -0
@@ 0,0 1,4 @@ 
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<features xmlns="http://karaf.apache.org/xmlns/features/v1.6.0" name="org.openhab.binding.lutron-mqtt">
+    <feature version="0.0.0"/>
+</features>

          
M src/main/java/org/openhab/binding/lutronmqtt/LutronMQTTBindingConstants.java +8 -4
@@ 12,11 12,13 @@ 
  */
 package org.openhab.binding.lutronmqtt;
 
-import com.google.common.collect.ImmutableSet;
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.smarthome.core.thing.ThingTypeUID;
 
+import java.util.Collections;
 import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * The {@link LutronMQTTBindingConstants} class defines common constants, which are

          
@@ 34,10 36,12 @@ public class LutronMQTTBindingConstants 
     public final static ThingTypeUID THING_TYPE_VARIABLE_FAN = new ThingTypeUID(BINDING_ID, "variableFan");
     public final static ThingTypeUID THING_TYPE_REMOTE = new ThingTypeUID(BINDING_ID, "remote");
 
-    public final static Set<ThingTypeUID> SUPPORTED_HUBS_UIDS = ImmutableSet.of(THING_TYPE_MQTTHUB);
+    public final static Set<ThingTypeUID> SUPPORTED_HUBS_UIDS = Collections.unmodifiableSet(
+            Stream.of(THING_TYPE_MQTTHUB).collect(Collectors.toSet()));
 
-    public final static Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = ImmutableSet.of(THING_TYPE_DIMMABLE_LIGHT,
-             THING_TYPE_VARIABLE_FAN, THING_TYPE_REMOTE);
+    public final static Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.unmodifiableSet(
+            Stream.of(THING_TYPE_DIMMABLE_LIGHT,
+             THING_TYPE_VARIABLE_FAN, THING_TYPE_REMOTE).collect(Collectors.toSet()));
 
     // List of all Channel ids
     public final static String PROPERTY_UUID = "uuid";

          
M src/main/java/org/openhab/binding/lutronmqtt/discovery/LutronMQTTHubDiscoveryParticipant.java +11 -2
@@ 44,9 44,13 @@ logger.warn("Discovery result: " + servi
             logger.warn("name: " + service.getName());
             logger.warn("qname: " + service.getQualifiedName());
             logger.warn("nice: " + service.getNiceTextString());
+            logger.warn("text: " + new String(service.getTextBytes()));
+
             Enumeration<String> pn = service.getPropertyNames();
-            while(pn.hasMoreElements())
-                logger.warn("prop: " + pn.nextElement());
+            while(pn.hasMoreElements()) {
+                String name;
+                logger.warn("prop: " + (name = pn.nextElement()) + " " + service.getPropertyString(name));
+            }
 
             logger.debug("Got discovered device.");
             if (true /*getDiscoveryServiceCallback() != null*/) {

          
@@ 69,6 73,11 @@ logger.warn("Discovery result: " + servi
                     String u = service.getPropertyString("uuid");
                     String s = service.getServer();
 
+                    if(s== null || s.isEmpty()) {
+                        String [] addrs = service.getHostAddresses();
+                        if(addrs.length > 0) s = addrs[0];
+                    }
+
                     if(u == null || s == null || u.isEmpty() || s.isEmpty()) // incomplete discovery result
                     {
                         logger.warn("Found lutron-mqtt service but missing data. Try restarting device.");

          
M src/main/java/org/openhab/binding/lutronmqtt/handler/LutronMQTTHubHandler.java +126 -114
@@ 12,22 12,25 @@ 
  */
 package org.openhab.binding.lutronmqtt.handler;
 
-import com.google.common.collect.ImmutableList;
 import com.google.gson.Gson;
+import jersey.repackaged.com.google.common.collect.ImmutableList;
 import org.eclipse.jdt.annotation.Nullable;
-import org.eclipse.paho.client.mqttv3.*;
-import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
 import org.eclipse.smarthome.config.core.Configuration;
 import org.eclipse.smarthome.core.thing.*;
 import org.eclipse.smarthome.core.thing.binding.BaseBridgeHandler;
 import org.eclipse.smarthome.core.types.Command;
+import org.eclipse.smarthome.io.transport.mqtt.*;
+import org.eclipse.smarthome.io.transport.mqtt.reconnect.PeriodicReconnectStrategy;
 import org.openhab.binding.lutronmqtt.internal.LutronMQTTConfiguration;
 import org.openhab.binding.lutronmqtt.model.LutronDevice;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URISyntaxException;
 import java.util.*;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
 

          
@@ 41,8 44,7 @@ import static org.openhab.binding.lutron
  *
  * @author William Welliver - Initial contribution
  */
-public class LutronMQTTHubHandler extends BaseBridgeHandler implements MqttCallback {
-
+public class LutronMQTTHubHandler extends BaseBridgeHandler implements MqttMessageSubscriber, MqttConnectionObserver {
     private final Logger logger = LoggerFactory.getLogger(LutronMQTTHubHandler.class);
 
     private Collection<DeviceStatusListener> deviceStatusListeners = new HashSet<>();

          
@@ 52,15 54,15 @@ public class LutronMQTTHubHandler extend
     @Nullable
     private LutronMQTTConfiguration config;
     private String token;
-    private MqttClient mqttClient;
+    private MqttBrokerConnection mqttClient;
     private Gson gson = new Gson();
     private Map<Integer, LutronDevice> devicesByLinkAddress = new HashMap<>();
-    private ScheduledFuture<?> reconnectJob;
     private ScheduledFuture<?> onlineTimeout;
     private ScheduledFuture<?> allItemsJob;
 
     public LutronMQTTHubHandler(Bridge thing) {
         super(thing);
+        logger.warn("LutronMQTTHubHandler create.");
     }
 
     @Override

          
@@ 70,72 72,86 @@ public class LutronMQTTHubHandler extend
         Map<String, String> properties = getThing().getProperties();
         token = (String) config.get(CONFIG_TOKEN);
 
-        final String uuid = properties.get(PROPERTY_UUID);
         final String broker = properties.get(PROPERTY_URL);
 
-        updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.NONE);
 
-        MemoryPersistence persistence = new MemoryPersistence();
         String clientId = "openhab-lutron-mqtt-" + (System.currentTimeMillis()/1000);
 
-        try {
-            if(mqttClient == null || !mqttClient.isConnected()) {
-                logger.info("Attempting to connect to MQTT Broker.");
-                MqttClient client = new MqttClient(broker, clientId, persistence);
-                MqttConnectOptions connOpts = new MqttConnectOptions();
-//                connOpts.setCleanSession(true);
-//                connOpts.setKeepAliveInterval(30);
-//                connOpts.setConnectionTimeout(90);
-                client.connect(connOpts);
-                mqttClient = client;
-                setupSubscriptions();
+            if(mqttClient == null || mqttClient.connectionState() == MqttConnectionState.DISCONNECTED) {
+                logger.warn("Attempting to connect to MQTT Broker.");
+                URI brokerUri = null;
+                try {
+                    brokerUri = new URI(broker);
+                } catch (URISyntaxException e) {
+                    logger.error("Lutron-MQTT broker url was invalid: " + broker);
+                    goOffline(ThingStatusDetail.CONFIGURATION_ERROR, "Lutron-MQTT broker url was invalid: " + broker);
+                    return;
+                }
+
+                MqttBrokerConnection brokerConnection = new MqttBrokerConnection(brokerUri.getHost(), brokerUri.getPort(), false, clientId);
+                brokerConnection.addConnectionObserver(this);
+                brokerConnection.setReconnectStrategy(new PeriodicReconnectStrategy());
+                updateStatus(ThingStatus.OFFLINE, "Preparing to connect to " + brokerUri.toASCIIString());
+
+                Boolean bool = null;
+                try {
+                    mqttClient = brokerConnection;
+                    bool = brokerConnection.start().get();
+                } catch (InterruptedException|ExecutionException e) {
+                    logger.warn("MQTT startup failed.", e);
+                }
+                logger.warn("MQTT startup returned " + bool);
             }
-        } catch (MqttException e) {
-            logger.error("Unable to connect to MQTT broker at " + broker, e);
-            goOffline(ThingStatusDetail.COMMUNICATION_ERROR, "Unable to connect to MQTT broker at broker");
-        }
+
+            //  logger.error("Unable to connect to MQTT broker at " + broker, e);
+          //  goOffline(ThingStatusDetail.COMMUNICATION_ERROR, "Unable to connect to MQTT broker at broker");
+
     }
 
-
+    protected void updateStatus(ThingStatus status, String statusDetail) {
+        this.updateStatus(status, ThingStatusDetail.NONE, (String)statusDetail);
+    }
 
     @Override
     public void dispose() {
         logger.info("Disposing of handler " + this);
         super.dispose();
-        try {
-            MqttClient cl = mqttClient;
-            cl.setCallback(null);
-            cl.unsubscribe(new String[] {"lutron/status", "lutron/events", "lutron/remote"});
-            cl.disconnectForcibly(3000);
-            cl.close();
-            mqttClient = null;
+
+            mqttClient.stop();
             cancelJobs();
 
-        } catch (MqttException e) {
-            logger.warn("Error while disconnecting", e);
-        }
+            mqttClient = null;
     }
 
     private void cancelJobs() {
-        if(reconnectJob != null && !reconnectJob.isCancelled())
-            reconnectJob.cancel(true);
         if(allItemsJob != null && !allItemsJob.isCancelled())
             allItemsJob.cancel(true);
-        if(onlineTimeout != null && !allItemsJob.isCancelled())
+        if(onlineTimeout != null && !onlineTimeout.isCancelled())
             onlineTimeout.cancel(true);
     }
 
     private void setupSubscriptions() {
-        mqttClient.setCallback(this);
         try {
-            mqttClient.subscribe(new String[] {"lutron/status", "lutron/events", "lutron/remote"});
-        } catch (MqttException e) {
-            logger.error("subscribe failed.", e);
-            goOffline(ThingStatusDetail.COMMUNICATION_ERROR, "Unable to subscribe to events");
+            mqttClient.unsubscribeAll().get();
+        } catch (InterruptedException|ExecutionException e) {
+            logger.warn("An error occurred while unsubscribing.", e);
         }
-
+        logger.info("Subscribing.");
+        for(String topic : new String[] {"lutron/status", "lutron/events", "lutron/remote"}) {
+            try {
+                logger.info("subscribing to " + topic);
+                if(!mqttClient.subscribe(topic, this).get()) {
+                    logger.error("subscribe failed.");
+                    goOffline(ThingStatusDetail.COMMUNICATION_ERROR, "Unable to subscribe to events");
+                }
+            } catch (InterruptedException|ExecutionException e) {
+                logger.warn("An error occurred while subscribing.", e);
+            }
+        }
+        logger.info("Subscribed.");
         cancelJobs();
 
+        logger.info("Scheduling item request.");
         allItemsJob = scheduler.schedule(new Runnable() {
             @Override
             public void run() {

          
@@ 145,13 161,18 @@ public class LutronMQTTHubHandler extend
     }
 
     private void requestAllItems() {
+        logger.warn("Requesting all items");
+        byte[] b = new byte[0];
         try {
-            byte[] b = ("{\"cmd\": \"GetDevices\", \"args\": {}}").getBytes("UTF-8");
-            mqttClient.publish("lutron/commands", (b), 0, false);
-        } catch (MqttException e) {
-            logger.warn("Error Sending message.", e);
+            b = ("{\"cmd\": \"GetDevices\", \"args\": {}}").getBytes("UTF-8");
         } catch (UnsupportedEncodingException e) {
-            logger.warn("Error encoding message.", e);
+            logger.warn("Unable to encode JSON.", e);
+        }
+        try {
+            Boolean res = mqttClient.publish("lutron/commands", (b), 0, false).get();
+            logger.warn("Publish returned " + res);
+        } catch(Exception e) {
+          logger.warn("Exception while publishing.", e);
         }
 
         allItemsJob = scheduler.schedule(new Runnable() {

          
@@ 190,44 211,8 @@ public class LutronMQTTHubHandler extend
     }
 
     @Override
-    public void connectionLost(Throwable throwable) {
-        goOffline(ThingStatusDetail.BRIDGE_OFFLINE, throwable.getMessage());
-        logger.warn("Lost connection to MQTT server. Will rety in 20 seconds.", throwable);
-        if(mqttClient != null) scheduleReconnect(20);
-    }
-
-    private void scheduleReconnect(int seconds) {
-       if(reconnectJob == null || reconnectJob.isDone()) {
-           reconnectJob = scheduler.schedule(new Runnable() {
-               @Override
-               public void run() {
-                   reconnect();
-               }
-           }, seconds, TimeUnit.SECONDS);
-       }
-    }
-
-    private void reconnect() {
-        if(mqttClient == null) {
-            logger.info("Skipping reconnect because MQTT client is null.");
-            return;
-        }
-        logger.info("Attempting to reconnect to MQTT server");
-            initialize();
-        ThingStatusInfo info = getThing().getStatusInfo();
-        if(info.getStatus() != ThingStatus.ONLINE &&
-                (info.getStatusDetail() == ThingStatusDetail.BRIDGE_OFFLINE ||
-                        info.getStatusDetail() == ThingStatusDetail.COMMUNICATION_ERROR
-                )) // we're not online but have a retryable status
-            scheduleReconnect(20);
-        else {
-            reconnectJob = null;
-        }
-    }
-
-    @Override
-    public void messageArrived(String s, MqttMessage mqttMessage) throws Exception {
-        logger.debug("messageArrived: " + s + " " + mqttMessage.toString());
+    public void processMessage(String s, byte[] mqttMessage) {
+        logger.warn("messageArrived: " + s + " " + mqttMessage.toString());
         switch(s) {
             case "lutron/status":
                 handleStatusMessage(mqttMessage);

          
@@ 241,9 226,9 @@ public class LutronMQTTHubHandler extend
         }
     }
 
-    private void handleGatewayEvent(MqttMessage mqttMessage) {
+    private void handleGatewayEvent(byte[] mqttMessage) {
         //logger.info("gateway event: " + new String(mqttMessage.getPayload()));
-        Map <String,Object> msg = gson.fromJson(new String(mqttMessage.getPayload()), HashMap.class);
+        Map <String,Object> msg = gson.fromJson(new String(mqttMessage), HashMap.class);
 
         if(msg.containsKey("cmd")) {
             String key = (String)msg.get("cmd");

          
@@ 297,13 282,8 @@ public class LutronMQTTHubHandler extend
     }
 
     protected void requestUpdateForDevice(int linkAddress) {
-        try {
             byte[] b = ("{\"cmd\":\"RuntimePropertyQuery\", \"args\":{\"Params\":[[" + linkAddress + ",15,[1]]]}}").getBytes();
-            MqttMessage message = new MqttMessage(b);
-            mqttClient.publish("lutron/commands", message);
-        } catch (MqttException e) {
-            logger.error("Error publishing message", e);
-        }
+            mqttClient.publish("lutron/commands", b);
     }
 
     protected void informDeviceListeners(LutronDevice device) {

          
@@ 318,17 298,16 @@ public class LutronMQTTHubHandler extend
         return devicesByLinkAddress.get(linkAddress);
     }
 
-    private void handleRemoteEvent(MqttMessage mqttMessage) {
-        logger.info("remote event: " + new String(mqttMessage.getPayload()));
+    private void handleRemoteEvent(byte[] mqttMessage) {
+        logger.info("remote event: " + new String(mqttMessage));
 
-        Map <String,Object> msg = gson.fromJson(new String(mqttMessage.getPayload()), HashMap.class);
+        Map <String,Object> msg = gson.fromJson(new String(mqttMessage), HashMap.class);
        // {"serial" : "C726CA", "action": "down", "button": "select"}
-
     }
 
-    private void handleStatusMessage(MqttMessage mqttMessage) {
-        logger.info("status message: " + new String(mqttMessage.getPayload()));
-        Map <String,Object> msg = gson.fromJson(new String(mqttMessage.getPayload()), HashMap.class);
+    private void handleStatusMessage(byte[] mqttMessage) {
+        logger.info("status message: " + new String(mqttMessage));
+        Map <String,Object> msg = gson.fromJson(new String(mqttMessage), HashMap.class);
         if(msg.containsKey("state") && "running".equals(msg.get("state"))) {
             if(onlineTimeout != null)
                 onlineTimeout.cancel(true);

          
@@ 344,21 323,54 @@ public class LutronMQTTHubHandler extend
 
     protected void onlineTimeoutOccurred() {
         goOffline(ThingStatusDetail.BRIDGE_OFFLINE, "Too long between status announcements.");
-    }
-
-    @Override
-    public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
-        // We really don't care too much about this status.
+        try {
+            mqttClient.stop().get();
+            Thread.sleep(5000);
+            initialize();
+        } catch(Exception e) {
+            logger.warn("An error occurred while restarting the service.", e);
+        }
     }
 
     public void setDesiredState(int deviceId, Map<String, Object> lightState) {
+        byte[] bytes = new byte[0];
         try {
-            byte[] bytes = (gson.toJson(lightState)).getBytes("UTF-8");
-           // MqttMessage message = new MqttMessage(bytes);
-            mqttClient.publish("lutron/commands", bytes, 0, false);
-            logger.info("Sent message.");
-        } catch (MqttException|UnsupportedEncodingException e) {
-            e.printStackTrace();
+            bytes = (gson.toJson(lightState)).getBytes("UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            logger.warn("Error encoding JSON.", e);
+        }
+        // MqttMessage message = new MqttMessage(bytes);
+        Boolean res = null;
+        try {
+            res = mqttClient.publish("lutron/commands", bytes, 0, false).get();
+            if(res)
+                logger.info("Sent message.");
+            else logger.warn("Failed to send message: " + new String(bytes));
+        } catch (InterruptedException|ExecutionException e) {
+            logger.warn("Error sending message.", e);
+        }
+    }
+
+    @Override
+    public void connectionStateChanged(MqttConnectionState mqttConnectionState, @Nullable Throwable throwable) {
+        if(mqttConnectionState == MqttConnectionState.CONNECTED) {
+            logger.info("MQTT connection state changed to CONNECTED.");
+            goOnline();
+            logger.info("Online");
+            scheduler.schedule(new Runnable() {
+                @Override
+                public void run() {
+                    setupSubscriptions();
+                    logger.info("Subscribed.");
+
+                }
+            },1, TimeUnit.SECONDS);
+        } else if (mqttConnectionState == MqttConnectionState.CONNECTING) {
+            goOffline(ThingStatusDetail.BRIDGE_OFFLINE, "MQTT Reconnecting");
+        } else if (mqttConnectionState == MqttConnectionState.DISCONNECTED) {
+            goOffline(ThingStatusDetail.BRIDGE_OFFLINE, "MQTT Disconnected");
+            logger.warn("Lost connection to MQTT server.");
+            cancelJobs();
         }
     }
 }

          
M src/main/java/org/openhab/binding/lutronmqtt/internal/LutronMQTTHandlerFactory.java +9 -0
@@ 17,6 17,7 @@ import static org.openhab.binding.lutron
 import java.util.*;
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
 import org.eclipse.smarthome.config.discovery.DiscoveryService;
 import org.eclipse.smarthome.core.thing.Bridge;
 import org.eclipse.smarthome.core.thing.ThingUID;

          
@@ 33,6 34,8 @@ import org.openhab.binding.lutronmqtt.ha
 import org.openhab.binding.lutronmqtt.handler.LutronMQTTVariableFanHandler;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.component.annotations.Component;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * The {@link LutronMQTTHandlerFactory} is responsible for creating things and thing

          
@@ 44,6 47,8 @@ import org.osgi.service.component.annota
 @NonNullByDefault
 public class LutronMQTTHandlerFactory extends BaseThingHandlerFactory {
 
+    private final static Logger logger = LoggerFactory.getLogger(LutronMQTTHandlerFactory.class);
+
     public final static Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = LutronMQTTBindingConstants.SUPPORTED_THING_TYPES_UIDS;
     private Map<ThingUID, ServiceRegistration<?>> discoveryServiceRegs = new HashMap<>();
 

          
@@ 53,11 58,15 @@ public class LutronMQTTHandlerFactory ex
     }
 
     @Override
+    @Nullable
     protected ThingHandler createHandler(Thing thing) {
 
         ThingTypeUID thingTypeUID = thing.getThingTypeUID();
 
+        logger.warn("Creating a handler for " + thing.getThingTypeUID() + ", " + thing.getLabel());
+
         if (thingTypeUID.equals(THING_TYPE_MQTTHUB)) {
+            logger.warn("Creating hub handler");
             LutronMQTTHubHandler handler = new LutronMQTTHubHandler((Bridge) thing);
             registerDeviceDiscoveryService(handler);
             return handler;

          
M ESH-INF/binding/binding.xml => src/main/resources/ESH-INF/binding/binding.xml +0 -0

        
M ESH-INF/i18n/lutronmqtt_xx_XX.properties => src/main/resources/ESH-INF/i18n/lutronmqtt_xx_XX.properties +0 -0

        
M ESH-INF/thing/hub.xml => src/main/resources/ESH-INF/thing/hub.xml +0 -0

        
M ESH-INF/thing/thing-types.xml => src/main/resources/ESH-INF/thing/thing-types.xml +0 -0