]> git.basschouten.com Git - openhab-addons.git/commitdiff
[nikohomecontrol] Discovery improvements (#12855)
authorMark Herwege <mherwege@users.noreply.github.com>
Fri, 3 Jun 2022 18:08:08 +0000 (20:08 +0200)
committerGitHub <noreply@github.com>
Fri, 3 Jun 2022 18:08:08 +0000 (20:08 +0200)
* Add discovery representation properties
* Recognized device types improvements
* Move discovery to thingHandlerService
* Discover multiple bridges in network
* Made device property names constants

Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
20 files changed:
bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/NikoHomeControlBindingConstants.java
bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/NikoHomeControlHandlerFactory.java
bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/discovery/NikoHomeControlBridgeDiscoveryService.java
bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/discovery/NikoHomeControlDiscoveryService.java
bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlActionHandler.java
bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlBridgeHandler.java
bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlBridgeHandler1.java
bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlBridgeHandler2.java
bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlEnergyMeterHandler.java
bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlThermostatHandler.java
bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NhcAction.java
bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NhcEnergyMeter.java
bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NhcThermostat.java
bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NikoHomeControlDiscover.java
bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc1/NikoHomeControlCommunication1.java
bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NhcAction2.java
bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NhcDevice2.java
bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NhcEnergyMeter2.java
bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NhcThermostat2.java
bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NikoHomeControlCommunication2.java

index 6a0eaead4decba4f28dc200e4578579a1eb2203e..17922fee545726b535de12beb4af0c4cd963c533 100644 (file)
@@ -90,4 +90,9 @@ public class NikoHomeControlBindingConstants {
     public static final String CONFIG_OVERRULETIME = "overruleTime";
 
     public static final String CONFIG_ENERGYMETER_ID = "energyMeterId";
+
+    // Thing properties
+    public static final String PROPERTY_DEVICE_TYPE = "deviceType";
+    public static final String PROPERTY_DEVICE_TECHNOLOGY = "deviceTechnology";
+    public static final String PROPERTY_DEVICE_MODEL = "deviceModel";
 }
index 6cb6c0d25fbd2ad89f31829b9ffa2863728e7628..fda292a180adba667bbd51cafc897ff2befdd21d 100644 (file)
@@ -14,29 +14,20 @@ package org.openhab.binding.nikohomecontrol.internal;
 
 import static org.openhab.binding.nikohomecontrol.internal.NikoHomeControlBindingConstants.*;
 
-import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.Map;
-
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.jdt.annotation.Nullable;
-import org.openhab.binding.nikohomecontrol.internal.discovery.NikoHomeControlDiscoveryService;
 import org.openhab.binding.nikohomecontrol.internal.handler.NikoHomeControlActionHandler;
-import org.openhab.binding.nikohomecontrol.internal.handler.NikoHomeControlBridgeHandler;
 import org.openhab.binding.nikohomecontrol.internal.handler.NikoHomeControlBridgeHandler1;
 import org.openhab.binding.nikohomecontrol.internal.handler.NikoHomeControlBridgeHandler2;
 import org.openhab.binding.nikohomecontrol.internal.handler.NikoHomeControlEnergyMeterHandler;
 import org.openhab.binding.nikohomecontrol.internal.handler.NikoHomeControlThermostatHandler;
-import org.openhab.core.config.discovery.DiscoveryService;
 import org.openhab.core.net.NetworkAddressService;
 import org.openhab.core.thing.Bridge;
 import org.openhab.core.thing.Thing;
 import org.openhab.core.thing.ThingTypeUID;
-import org.openhab.core.thing.ThingUID;
 import org.openhab.core.thing.binding.BaseThingHandlerFactory;
 import org.openhab.core.thing.binding.ThingHandler;
 import org.openhab.core.thing.binding.ThingHandlerFactory;
-import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Reference;
 
@@ -47,14 +38,12 @@ import org.osgi.service.component.annotations.Reference;
  * @author Mark Herwege - Initial Contribution
  */
 
-@Component(service = ThingHandlerFactory.class, configurationPid = "binding.nikohomecontrol")
 @NonNullByDefault
+@Component(service = ThingHandlerFactory.class, configurationPid = "binding.nikohomecontrol")
 public class NikoHomeControlHandlerFactory extends BaseThingHandlerFactory {
 
     private @NonNullByDefault({}) NetworkAddressService networkAddressService;
 
-    private final Map<ThingUID, ServiceRegistration<?>> discoveryServiceRegs = new HashMap<>();
-
     @Override
     public boolean supportsThingType(ThingTypeUID thingTypeUID) {
         return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID) || BRIDGE_THING_TYPES_UIDS.contains(thingTypeUID);
@@ -63,14 +52,11 @@ public class NikoHomeControlHandlerFactory extends BaseThingHandlerFactory {
     @Override
     protected @Nullable ThingHandler createHandler(Thing thing) {
         if (BRIDGE_THING_TYPES_UIDS.contains(thing.getThingTypeUID())) {
-            NikoHomeControlBridgeHandler handler;
             if (BRIDGEII_THING_TYPE.equals(thing.getThingTypeUID())) {
-                handler = new NikoHomeControlBridgeHandler2((Bridge) thing, networkAddressService);
+                return new NikoHomeControlBridgeHandler2((Bridge) thing, networkAddressService);
             } else {
-                handler = new NikoHomeControlBridgeHandler1((Bridge) thing);
+                return new NikoHomeControlBridgeHandler1((Bridge) thing);
             }
-            registerNikoHomeControlDiscoveryService(handler);
-            return handler;
         } else if (THING_TYPE_THERMOSTAT.equals(thing.getThingTypeUID())) {
             return new NikoHomeControlThermostatHandler(thing);
         } else if (THING_TYPE_ENERGYMETER.equals(thing.getThingTypeUID())) {
@@ -82,29 +68,6 @@ public class NikoHomeControlHandlerFactory extends BaseThingHandlerFactory {
         return null;
     }
 
-    private synchronized void registerNikoHomeControlDiscoveryService(NikoHomeControlBridgeHandler bridgeHandler) {
-        NikoHomeControlDiscoveryService nhcDiscoveryService = new NikoHomeControlDiscoveryService(bridgeHandler);
-        discoveryServiceRegs.put(bridgeHandler.getThing().getUID(), bundleContext
-                .registerService(DiscoveryService.class.getName(), nhcDiscoveryService, new Hashtable<>()));
-        nhcDiscoveryService.activate();
-    }
-
-    @Override
-    protected synchronized void removeHandler(ThingHandler thingHandler) {
-        if (thingHandler instanceof NikoHomeControlBridgeHandler) {
-            ServiceRegistration<?> serviceReg = discoveryServiceRegs.remove(thingHandler.getThing().getUID());
-            if (serviceReg != null) {
-                // remove discovery service, if bridge handler is removed
-                NikoHomeControlDiscoveryService service = (NikoHomeControlDiscoveryService) bundleContext
-                        .getService(serviceReg.getReference());
-                serviceReg.unregister();
-                if (service != null) {
-                    service.deactivate();
-                }
-            }
-        }
-    }
-
     @Reference
     protected void setNetworkAddressService(NetworkAddressService networkAddressService) {
         this.networkAddressService = networkAddressService;
index f9891ce1010a46b51e1402fd90f129780d9b4166..f3d304c9ed10a9e5778fc847ef1a1f19a6e546e2 100644 (file)
@@ -40,8 +40,8 @@ import org.slf4j.LoggerFactory;
  *
  * @author Mark Herwege - Initial Contribution
  */
-@Component(service = DiscoveryService.class, configurationPid = "discovery.nikohomecontrol")
 @NonNullByDefault
+@Component(service = DiscoveryService.class, configurationPid = "discovery.nikohomecontrol")
 public class NikoHomeControlBridgeDiscoveryService extends AbstractDiscoveryService {
 
     private final Logger logger = LoggerFactory.getLogger(NikoHomeControlBridgeDiscoveryService.class);
@@ -50,11 +50,11 @@ public class NikoHomeControlBridgeDiscoveryService extends AbstractDiscoveryServ
 
     private @NonNullByDefault({}) NetworkAddressService networkAddressService;
 
-    private static final int TIMEOUT = 5;
-    private static final int REFRESH_INTERVAL = 60;
+    private static final int TIMOUT_S = 5;
+    private static final int REFRESH_INTERVAL_S = 60;
 
     public NikoHomeControlBridgeDiscoveryService() {
-        super(NikoHomeControlBindingConstants.BRIDGE_THING_TYPES_UIDS, TIMEOUT);
+        super(NikoHomeControlBindingConstants.BRIDGE_THING_TYPES_UIDS, TIMOUT_S);
         logger.debug("bridge discovery service started");
     }
 
@@ -70,13 +70,18 @@ public class NikoHomeControlBridgeDiscoveryService extends AbstractDiscoveryServ
             }
             logger.debug("discovery broadcast on {}", broadcastAddr);
             NikoHomeControlDiscover nhcDiscover = new NikoHomeControlDiscover(broadcastAddr);
-            if (nhcDiscover.isNhcII()) {
-                addNhcIIBridge(nhcDiscover.getAddr(), nhcDiscover.getNhcBridgeId());
-            } else {
-                addNhcIBridge(nhcDiscover.getAddr(), nhcDiscover.getNhcBridgeId());
+            for (String nhcController : nhcDiscover.getNhcBridgeIds()) {
+                InetAddress addr = nhcDiscover.getAddr(nhcController);
+                if (addr != null) {
+                    if (nhcDiscover.isNhcII(nhcController)) {
+                        addNhcIIBridge(addr, nhcController);
+                    } else {
+                        addNhcIBridge(addr, nhcController);
+                    }
+                }
             }
         } catch (IOException e) {
-            logger.debug("no bridge found.");
+            logger.debug("bridge discovery IO exception");
         }
     }
 
@@ -87,7 +92,8 @@ public class NikoHomeControlBridgeDiscoveryService extends AbstractDiscoveryServ
         ThingUID uid = new ThingUID(BINDING_ID, "bridge", bridgeId);
 
         DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(uid).withLabel(bridgeName)
-                .withProperty(CONFIG_HOST_NAME, addr.getHostAddress()).build();
+                .withProperty(CONFIG_HOST_NAME, addr.getHostAddress()).withRepresentationProperty(CONFIG_HOST_NAME)
+                .build();
         thingDiscovered(discoveryResult);
     }
 
@@ -98,7 +104,8 @@ public class NikoHomeControlBridgeDiscoveryService extends AbstractDiscoveryServ
         ThingUID uid = new ThingUID(BINDING_ID, "bridge2", bridgeId);
 
         DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(uid).withLabel(bridgeName)
-                .withProperty(CONFIG_HOST_NAME, addr.getHostAddress()).build();
+                .withProperty(CONFIG_HOST_NAME, addr.getHostAddress()).withRepresentationProperty(CONFIG_HOST_NAME)
+                .build();
         thingDiscovered(discoveryResult);
     }
 
@@ -115,10 +122,10 @@ public class NikoHomeControlBridgeDiscoveryService extends AbstractDiscoveryServ
 
     @Override
     protected void startBackgroundDiscovery() {
-        logger.debug("Start background bridge discovery");
+        logger.debug("Start bridge background discovery");
         ScheduledFuture<?> job = nhcDiscoveryJob;
         if (job == null || job.isCancelled()) {
-            nhcDiscoveryJob = scheduler.scheduleWithFixedDelay(this::discoverBridge, 0, REFRESH_INTERVAL,
+            nhcDiscoveryJob = scheduler.scheduleWithFixedDelay(this::discoverBridge, 0, REFRESH_INTERVAL_S,
                     TimeUnit.SECONDS);
         }
     }
index 5b8c4a7c1aaf64fbb7c0719f41cdb55a0af3ff4a..07bc7ba77d27be8a3d3755092b36eef6c067865a 100644 (file)
@@ -14,8 +14,10 @@ package org.openhab.binding.nikohomecontrol.internal.discovery;
 
 import static org.openhab.binding.nikohomecontrol.internal.NikoHomeControlBindingConstants.*;
 
-import java.util.Date;
+import java.time.Instant;
 import java.util.Map;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.jdt.annotation.Nullable;
@@ -27,6 +29,8 @@ import org.openhab.binding.nikohomecontrol.internal.protocol.NikoHomeControlComm
 import org.openhab.core.config.discovery.AbstractDiscoveryService;
 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
 import org.openhab.core.thing.ThingUID;
+import org.openhab.core.thing.binding.ThingHandler;
+import org.openhab.core.thing.binding.ThingHandlerService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -37,43 +41,52 @@ import org.slf4j.LoggerFactory;
  * @author Mark Herwege - Initial Contribution
  */
 @NonNullByDefault
-public class NikoHomeControlDiscoveryService extends AbstractDiscoveryService {
+public class NikoHomeControlDiscoveryService extends AbstractDiscoveryService implements ThingHandlerService {
 
     private final Logger logger = LoggerFactory.getLogger(NikoHomeControlDiscoveryService.class);
 
-    private static final int TIMEOUT = 5;
+    private volatile @Nullable ScheduledFuture<?> nhcDiscoveryJob;
 
-    private ThingUID bridgeUID;
-    private NikoHomeControlBridgeHandler handler;
+    private static final int TIMEOUT_S = 5;
+    private static final int INITIAL_DELAY_S = 5; // initial delay for polling to allow time for initial request to NHC
+                                                  // controller to complete
+    private static final int REFRESH_INTERVAL_S = 60;
 
-    public NikoHomeControlDiscoveryService(NikoHomeControlBridgeHandler handler) {
-        super(SUPPORTED_THING_TYPES_UIDS, TIMEOUT, false);
-        logger.debug("discovery service {}", handler);
-        bridgeUID = handler.getThing().getUID();
-        this.handler = handler;
+    private @Nullable ThingUID bridgeUID;
+    private @Nullable NikoHomeControlBridgeHandler handler;
+
+    public NikoHomeControlDiscoveryService() {
+        super(SUPPORTED_THING_TYPES_UIDS, TIMEOUT_S, true);
+        logger.debug("device discovery service started");
     }
 
+    @Override
     public void activate() {
-        handler.setNhcDiscovery(this);
+        startBackgroundDiscovery();
     }
 
     @Override
     public void deactivate() {
-        removeOlderResults(new Date().getTime());
-        handler.setNhcDiscovery(null);
+        removeOlderResults(Instant.now().toEpochMilli());
+        super.deactivate();
     }
 
     /**
      * Discovers devices connected to a Niko Home Control controller
      */
     public void discoverDevices() {
-        NikoHomeControlCommunication nhcComm = handler.getCommunication();
+        NikoHomeControlBridgeHandler bridgeHandler = handler;
+        if (bridgeHandler == null) {
+            return;
+        }
+
+        NikoHomeControlCommunication nhcComm = bridgeHandler.getCommunication();
 
         if ((nhcComm == null) || !nhcComm.communicationActive()) {
             logger.warn("not connected");
             return;
         }
-        logger.debug("getting devices on {}", handler.getThing().getUID().getId());
+        logger.debug("getting devices on {}", bridgeHandler.getThing().getUID().getId());
 
         Map<String, NhcAction> actions = nhcComm.getActions();
 
@@ -83,20 +96,21 @@ public class NikoHomeControlDiscoveryService extends AbstractDiscoveryService {
 
             switch (nhcAction.getType()) {
                 case TRIGGER:
-                    addActionDevice(new ThingUID(THING_TYPE_PUSHBUTTON, handler.getThing().getUID(), actionId),
+                    addActionDevice(new ThingUID(THING_TYPE_PUSHBUTTON, bridgeHandler.getThing().getUID(), actionId),
                             actionId, thingName, thingLocation);
                     break;
                 case RELAY:
-                    addActionDevice(new ThingUID(THING_TYPE_ON_OFF_LIGHT, handler.getThing().getUID(), actionId),
+                    addActionDevice(new ThingUID(THING_TYPE_ON_OFF_LIGHT, bridgeHandler.getThing().getUID(), actionId),
                             actionId, thingName, thingLocation);
                     break;
                 case DIMMER:
-                    addActionDevice(new ThingUID(THING_TYPE_DIMMABLE_LIGHT, handler.getThing().getUID(), actionId),
+                    addActionDevice(
+                            new ThingUID(THING_TYPE_DIMMABLE_LIGHT, bridgeHandler.getThing().getUID(), actionId),
                             actionId, thingName, thingLocation);
                     break;
                 case ROLLERSHUTTER:
-                    addActionDevice(new ThingUID(THING_TYPE_BLIND, handler.getThing().getUID(), actionId), actionId,
-                            thingName, thingLocation);
+                    addActionDevice(new ThingUID(THING_TYPE_BLIND, bridgeHandler.getThing().getUID(), actionId),
+                            actionId, thingName, thingLocation);
                     break;
                 default:
                     logger.debug("unrecognized action type {} for {} {}", nhcAction.getType(), actionId, thingName);
@@ -108,7 +122,7 @@ public class NikoHomeControlDiscoveryService extends AbstractDiscoveryService {
         thermostats.forEach((thermostatId, nhcThermostat) -> {
             String thingName = nhcThermostat.getName();
             String thingLocation = nhcThermostat.getLocation();
-            addThermostatDevice(new ThingUID(THING_TYPE_THERMOSTAT, handler.getThing().getUID(), thermostatId),
+            addThermostatDevice(new ThingUID(THING_TYPE_THERMOSTAT, bridgeHandler.getThing().getUID(), thermostatId),
                     thermostatId, thingName, thingLocation);
         });
 
@@ -116,14 +130,16 @@ public class NikoHomeControlDiscoveryService extends AbstractDiscoveryService {
 
         energyMeters.forEach((energyMeterId, nhcEnergyMeter) -> {
             String thingName = nhcEnergyMeter.getName();
-            addEnergyMeterDevice(new ThingUID(THING_TYPE_ENERGYMETER, handler.getThing().getUID(), energyMeterId),
-                    energyMeterId, thingName);
+            String thingLocation = nhcEnergyMeter.getLocation();
+            addEnergyMeterDevice(new ThingUID(THING_TYPE_ENERGYMETER, bridgeHandler.getThing().getUID(), energyMeterId),
+                    energyMeterId, thingName, thingLocation);
         });
     }
 
     private void addActionDevice(ThingUID uid, String actionId, String thingName, @Nullable String thingLocation) {
         DiscoveryResultBuilder discoveryResultBuilder = DiscoveryResultBuilder.create(uid).withBridge(bridgeUID)
-                .withLabel(thingName).withProperty(CONFIG_ACTION_ID, actionId);
+                .withLabel(thingName).withProperty(CONFIG_ACTION_ID, actionId)
+                .withRepresentationProperty(CONFIG_ACTION_ID);
         if (thingLocation != null) {
             discoveryResultBuilder.withProperty("Location", thingLocation);
         }
@@ -133,16 +149,22 @@ public class NikoHomeControlDiscoveryService extends AbstractDiscoveryService {
     private void addThermostatDevice(ThingUID uid, String thermostatId, String thingName,
             @Nullable String thingLocation) {
         DiscoveryResultBuilder discoveryResultBuilder = DiscoveryResultBuilder.create(uid).withBridge(bridgeUID)
-                .withLabel(thingName).withProperty(CONFIG_THERMOSTAT_ID, thermostatId);
+                .withLabel(thingName).withProperty(CONFIG_THERMOSTAT_ID, thermostatId)
+                .withRepresentationProperty(CONFIG_THERMOSTAT_ID);
         if (thingLocation != null) {
             discoveryResultBuilder.withProperty("Location", thingLocation);
         }
         thingDiscovered(discoveryResultBuilder.build());
     }
 
-    private void addEnergyMeterDevice(ThingUID uid, String energyMeterId, String thingName) {
+    private void addEnergyMeterDevice(ThingUID uid, String energyMeterId, String thingName,
+            @Nullable String thingLocation) {
         DiscoveryResultBuilder discoveryResultBuilder = DiscoveryResultBuilder.create(uid).withBridge(bridgeUID)
-                .withLabel(thingName).withProperty(CONFIG_ENERGYMETER_ID, energyMeterId);
+                .withLabel(thingName).withProperty(CONFIG_ENERGYMETER_ID, energyMeterId)
+                .withRepresentationProperty(CONFIG_ENERGYMETER_ID);
+        if (thingLocation != null) {
+            discoveryResultBuilder.withProperty("Location", thingLocation);
+        }
         thingDiscovered(discoveryResultBuilder.build());
     }
 
@@ -156,4 +178,37 @@ public class NikoHomeControlDiscoveryService extends AbstractDiscoveryService {
         super.stopScan();
         removeOlderResults(getTimestampOfLastScan());
     }
+
+    @Override
+    protected void startBackgroundDiscovery() {
+        logger.debug("Start device background discovery");
+        ScheduledFuture<?> job = nhcDiscoveryJob;
+        if (job == null || job.isCancelled()) {
+            nhcDiscoveryJob = scheduler.scheduleWithFixedDelay(this::discoverDevices, INITIAL_DELAY_S,
+                    REFRESH_INTERVAL_S, TimeUnit.SECONDS);
+        }
+    }
+
+    @Override
+    protected void stopBackgroundDiscovery() {
+        logger.debug("Stop device background discovery");
+        ScheduledFuture<?> job = nhcDiscoveryJob;
+        if (job != null && !job.isCancelled()) {
+            job.cancel(true);
+            nhcDiscoveryJob = null;
+        }
+    }
+
+    @Override
+    public void setThingHandler(@Nullable ThingHandler handler) {
+        if (handler instanceof NikoHomeControlBridgeHandler) {
+            this.handler = (NikoHomeControlBridgeHandler) handler;
+            bridgeUID = handler.getThing().getUID();
+        }
+    }
+
+    @Override
+    public @Nullable ThingHandler getThingHandler() {
+        return handler;
+    }
 }
index d96c172fa5ffcacfd2260743fdae8448f91c5899..df5bb9544e2e83b1748fd04333ab001ece040b52 100644 (file)
@@ -238,7 +238,7 @@ public class NikoHomeControlActionHandler extends BaseThingHandler implements Nh
 
             nhcAction.setEventHandler(this);
 
-            updateProperties();
+            updateProperties(nhcAction);
 
             String actionLocation = nhcAction.getLocation();
             if (thing.getLocation() == null) {
@@ -260,14 +260,9 @@ public class NikoHomeControlActionHandler extends BaseThingHandler implements Nh
         });
     }
 
-    private void updateProperties() {
-        NhcAction nhcAction = this.nhcAction;
-        if (nhcAction == null) {
-            logger.debug("action with ID {} not initialized", actionId);
-            return;
-        }
-
+    private void updateProperties(NhcAction nhcAction) {
         Map<String, String> properties = new HashMap<>();
+
         properties.put("type", String.valueOf(nhcAction.getType()));
         if (getThing().getThingTypeUID() == THING_TYPE_BLIND) {
             properties.put("timeToOpen", String.valueOf(nhcAction.getOpenTime()));
@@ -276,8 +271,9 @@ public class NikoHomeControlActionHandler extends BaseThingHandler implements Nh
 
         if (nhcAction instanceof NhcAction2) {
             NhcAction2 action = (NhcAction2) nhcAction;
-            properties.put("model", action.getModel());
-            properties.put("technology", action.getTechnology());
+            properties.put(PROPERTY_DEVICE_TYPE, action.getDeviceType());
+            properties.put(PROPERTY_DEVICE_TECHNOLOGY, action.getDeviceTechnology());
+            properties.put(PROPERTY_DEVICE_MODEL, action.getDeviceModel());
         }
 
         thing.setProperties(properties);
index f1b688bab0d7486b8bba175c5a3be5ae5735e7b8..467bedb0923dcc0a77daf5608dc672db2e104756 100644 (file)
@@ -16,8 +16,10 @@ import static org.openhab.binding.nikohomecontrol.internal.NikoHomeControlBindin
 
 import java.net.InetAddress;
 import java.net.UnknownHostException;
+import java.util.Collection;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Set;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
 
@@ -32,6 +34,7 @@ import org.openhab.core.thing.ChannelUID;
 import org.openhab.core.thing.ThingStatus;
 import org.openhab.core.thing.ThingStatusDetail;
 import org.openhab.core.thing.binding.BaseBridgeHandler;
+import org.openhab.core.thing.binding.ThingHandlerService;
 import org.openhab.core.types.Command;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -39,8 +42,7 @@ import org.slf4j.LoggerFactory;
 /**
  * {@link NikoHomeControlBridgeHandler} is an abstract class representing a handler to all different interfaces to the
  * Niko Home Control System. {@link NikoHomeControlBridgeHandler1} or {@link NikoHomeControlBridgeHandler2} should be
- * used for the respective
- * version of Niko Home Control.
+ * used for the respective version of Niko Home Control.
  *
  * @author Mark Herwege - Initial Contribution
  */
@@ -49,14 +51,10 @@ public abstract class NikoHomeControlBridgeHandler extends BaseBridgeHandler imp
 
     private final Logger logger = LoggerFactory.getLogger(NikoHomeControlBridgeHandler.class);
 
-    protected @NonNullByDefault({}) NikoHomeControlBridgeConfig config;
-
     protected @Nullable NikoHomeControlCommunication nhcComm;
 
     private volatile @Nullable ScheduledFuture<?> refreshTimer;
 
-    protected volatile @Nullable NikoHomeControlDiscoveryService nhcDiscovery;
-
     public NikoHomeControlBridgeHandler(Bridge nikoHomeControlBridge) {
         super(nikoHomeControlBridge);
     }
@@ -90,22 +88,15 @@ public abstract class NikoHomeControlBridgeHandler extends BaseBridgeHandler imp
 
             updateStatus(ThingStatus.ONLINE);
 
-            int refreshInterval = config.refresh;
+            int refreshInterval = getConfig().as(NikoHomeControlBridgeConfig.class).refresh;
             setupRefreshTimer(refreshInterval);
-
-            NikoHomeControlDiscoveryService discovery = nhcDiscovery;
-            if (discovery != null) {
-                discovery.discoverDevices();
-            } else {
-                logger.debug("cannot discover devices, discovery service not started");
-            }
         });
     }
 
     /**
      * Schedule future communication refresh.
      *
-     * @param interval_config Time before refresh in minutes.
+     * @param refreshInterval Time before refresh in minutes.
      */
     private void setupRefreshTimer(int refreshInterval) {
         ScheduledFuture<?> timer = refreshTimer;
@@ -163,7 +154,7 @@ public abstract class NikoHomeControlBridgeHandler extends BaseBridgeHandler imp
     public void controllerOnline() {
         bridgeOnline();
 
-        int refreshInterval = config.refresh;
+        int refreshInterval = getConfig().as(NikoHomeControlBridgeConfig.class).refresh;
         if (refreshTimer == null) {
             setupRefreshTimer(refreshInterval);
         }
@@ -199,13 +190,11 @@ public abstract class NikoHomeControlBridgeHandler extends BaseBridgeHandler imp
         }
 
         Configuration configuration = editConfiguration();
-        for (Entry<String, Object> configurationParmeter : configurationParameters.entrySet()) {
-            configuration.put(configurationParmeter.getKey(), configurationParmeter.getValue());
+        for (Entry<String, Object> configurationParameter : configurationParameters.entrySet()) {
+            configuration.put(configurationParameter.getKey(), configurationParameter.getValue());
         }
         updateConfiguration(configuration);
 
-        setConfig();
-
         scheduler.submit(() -> {
             comm.restartCommunication();
             if (!comm.communicationActive()) {
@@ -217,20 +206,11 @@ public abstract class NikoHomeControlBridgeHandler extends BaseBridgeHandler imp
 
             updateStatus(ThingStatus.ONLINE);
 
-            int refreshInterval = config.refresh;
+            int refreshInterval = getConfig().as(NikoHomeControlBridgeConfig.class).refresh;
             setupRefreshTimer(refreshInterval);
         });
     }
 
-    /**
-     * Set discovery service handler to be able to start discovery after bridge initialization.
-     *
-     * @param nhcDiscovery
-     */
-    public void setNhcDiscovery(@Nullable NikoHomeControlDiscoveryService nhcDiscovery) {
-        this.nhcDiscovery = nhcDiscovery;
-    }
-
     @Override
     public void alarmEvent(String alarmText) {
         logger.debug("triggering alarm channel with {}", alarmText);
@@ -262,6 +242,7 @@ public abstract class NikoHomeControlBridgeHandler extends BaseBridgeHandler imp
     @Override
     public @Nullable InetAddress getAddr() {
         InetAddress addr = null;
+        NikoHomeControlBridgeConfig config = getConfig().as(NikoHomeControlBridgeConfig.class);
         try {
             addr = InetAddress.getByName(config.addr);
         } catch (UnknownHostException e) {
@@ -272,10 +253,11 @@ public abstract class NikoHomeControlBridgeHandler extends BaseBridgeHandler imp
 
     @Override
     public int getPort() {
-        return config.port;
+        return getConfig().as(NikoHomeControlBridgeConfig.class).port;
     }
 
-    protected synchronized void setConfig() {
-        config = getConfig().as(NikoHomeControlBridgeConfig.class);
+    @Override
+    public Collection<Class<? extends ThingHandlerService>> getServices() {
+        return Set.of(NikoHomeControlDiscoveryService.class);
     }
 }
index 004620a3abb71c4d93642a58ef8a703718b5c65e..958681befa1b530cb2aa2b6138a10027412ab0cf 100644 (file)
@@ -45,7 +45,6 @@ public class NikoHomeControlBridgeHandler1 extends NikoHomeControlBridgeHandler
     public void initialize() {
         logger.debug("initializing bridge handler");
 
-        setConfig();
         InetAddress addr = getAddr();
         int port = getPort();
 
index 0b11604a237531955ac5e45b29a6520d5fb07b50..4e86d9b2b7be6f94085c4ebeb069583c2889b4ea 100644 (file)
@@ -59,8 +59,6 @@ public class NikoHomeControlBridgeHandler2 extends NikoHomeControlBridgeHandler
     public void initialize() {
         logger.debug("initializing NHC II bridge handler");
 
-        setConfig();
-
         Date expiryDate = getTokenExpiryDate();
         if (expiryDate == null) {
             if (getToken().isEmpty()) {
@@ -161,12 +159,12 @@ public class NikoHomeControlBridgeHandler2 extends NikoHomeControlBridgeHandler
 
     @Override
     public String getProfile() {
-        return ((NikoHomeControlBridgeConfig2) config).profile;
+        return getConfig().as(NikoHomeControlBridgeConfig2.class).profile;
     }
 
     @Override
     public String getToken() {
-        String token = ((NikoHomeControlBridgeConfig2) config).password;
+        String token = getConfig().as(NikoHomeControlBridgeConfig2.class).password;
         if (token.isEmpty()) {
             logger.debug("no JWT token set.");
         }
@@ -227,9 +225,4 @@ public class NikoHomeControlBridgeHandler2 extends NikoHomeControlBridgeHandler
 
         return null;
     }
-
-    @Override
-    protected synchronized void setConfig() {
-        config = getConfig().as(NikoHomeControlBridgeConfig2.class);
-    }
 }
index e4a6d7947376141a3f4d8fccd85cad5e9b7de576..6aee1157f7ccfe043310bc2995512daa627c5a9b 100644 (file)
@@ -12,7 +12,7 @@
  */
 package org.openhab.binding.nikohomecontrol.internal.handler;
 
-import static org.openhab.binding.nikohomecontrol.internal.NikoHomeControlBindingConstants.CHANNEL_POWER;
+import static org.openhab.binding.nikohomecontrol.internal.NikoHomeControlBindingConstants.*;
 import static org.openhab.core.types.RefreshType.REFRESH;
 
 import java.util.HashMap;
@@ -102,7 +102,12 @@ public class NikoHomeControlEnergyMeterHandler extends BaseThingHandler implemen
 
             nhcEnergyMeter.setEventHandler(this);
 
-            updateProperties();
+            updateProperties(nhcEnergyMeter);
+
+            String location = nhcEnergyMeter.getLocation();
+            if (thing.getLocation() == null) {
+                thing.setLocation(location);
+            }
 
             // Subscribing to power readings starts an intensive data flow, therefore only do it when there is an item
             // linked to the channel
@@ -132,13 +137,14 @@ public class NikoHomeControlEnergyMeterHandler extends BaseThingHandler implemen
         }
     }
 
-    private void updateProperties() {
+    private void updateProperties(NhcEnergyMeter nhcEnergyMeter) {
         Map<String, String> properties = new HashMap<>();
 
         if (nhcEnergyMeter instanceof NhcEnergyMeter2) {
             NhcEnergyMeter2 energyMeter = (NhcEnergyMeter2) nhcEnergyMeter;
-            properties.put("model", energyMeter.getModel());
-            properties.put("technology", energyMeter.getTechnology());
+            properties.put(PROPERTY_DEVICE_TYPE, energyMeter.getDeviceType());
+            properties.put(PROPERTY_DEVICE_TECHNOLOGY, energyMeter.getDeviceTechnology());
+            properties.put(PROPERTY_DEVICE_MODEL, energyMeter.getDeviceModel());
         }
 
         thing.setProperties(properties);
index a8f2b45b8c7487800f832674da9222229c97f966..0debc0e7a4c08e7037cd8648821e6f2bd3c08eb2 100644 (file)
@@ -181,7 +181,7 @@ public class NikoHomeControlThermostatHandler extends BaseThingHandler implement
 
             nhcThermostat.setEventHandler(this);
 
-            updateProperties();
+            updateProperties(nhcThermostat);
 
             String thermostatLocation = nhcThermostat.getLocation();
             if (thing.getLocation() == null) {
@@ -204,13 +204,14 @@ public class NikoHomeControlThermostatHandler extends BaseThingHandler implement
         });
     }
 
-    private void updateProperties() {
+    private void updateProperties(NhcThermostat nhcThermostat) {
         Map<String, String> properties = new HashMap<>();
 
         if (nhcThermostat instanceof NhcThermostat2) {
             NhcThermostat2 thermostat = (NhcThermostat2) nhcThermostat;
-            properties.put("model", thermostat.getModel());
-            properties.put("technology", thermostat.getTechnology());
+            properties.put(PROPERTY_DEVICE_TYPE, thermostat.getDeviceType());
+            properties.put(PROPERTY_DEVICE_TECHNOLOGY, thermostat.getDeviceTechnology());
+            properties.put(PROPERTY_DEVICE_MODEL, thermostat.getDeviceModel());
         }
 
         thing.setProperties(properties);
index d962131628e510cc4fb54e8b89f55f908d9136da..bda23e28dfb6b352f06c303942c1621c3fc825a3 100644 (file)
@@ -66,9 +66,9 @@ public abstract class NhcAction {
     }
 
     /**
-     * Get the id of the action.
+     * Get id of action.
      *
-     * @return the id
+     * @return id
      */
     public String getId() {
         return id;
@@ -83,6 +83,15 @@ public abstract class NhcAction {
         return name;
     }
 
+    /**
+     * Set name of action.
+     *
+     * @param name action name
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
     /**
      * Get type of action identified.
      * <p>
@@ -103,6 +112,15 @@ public abstract class NhcAction {
         return location;
     }
 
+    /**
+     * Set location name of action.
+     *
+     * @param location action location name
+     */
+    public void setLocation(@Nullable String location) {
+        this.location = location;
+    }
+
     /**
      * Get state of action.
      * <p>
index af07cd417c4a8af8969407c072b1e5a660f8c6e0..89cacbf69504395495db313b4deb97d2654bc9db 100644 (file)
@@ -36,14 +36,16 @@ public abstract class NhcEnergyMeter {
 
     protected String id;
     protected String name;
+    protected @Nullable String location;
     // This can be null as long as we do not receive power readings
     protected volatile @Nullable Integer power = null;
 
     private @Nullable NhcEnergyMeterEvent eventHandler;
 
-    protected NhcEnergyMeter(String id, String name, NikoHomeControlCommunication nhcComm) {
+    protected NhcEnergyMeter(String id, String name, @Nullable String location, NikoHomeControlCommunication nhcComm) {
         this.id = id;
         this.name = name;
+        this.location = location;
         this.nhcComm = nhcComm;
     }
 
@@ -84,23 +86,50 @@ public abstract class NhcEnergyMeter {
     }
 
     /**
-     * Get the id of the energyMeters meter.
+     * Get id of meter.
      *
-     * @return the id
+     * @return id
      */
     public String getId() {
         return id;
     }
 
     /**
-     * Get name of the energyMeters meter.
+     * Get name of meter.
      *
-     * @return energyMeters meter name
+     * @return energyMeter name
      */
     public String getName() {
         return name;
     }
 
+    /**
+     * Set name of meter.
+     *
+     * @param name meter name
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Get location name of meter.
+     *
+     * @return location energyMeter location
+     */
+    public @Nullable String getLocation() {
+        return location;
+    }
+
+    /**
+     * Set location name of meter.
+     *
+     * @param location meter location name
+     */
+    public void setLocation(@Nullable String location) {
+        this.location = location;
+    }
+
     /**
      * @return the power in W (positive for consumption, negative for production), return null if no reading received
      *         yet
index 91d1818f0a9f64557e3644118a1e9a5b5f1feb2c..6166fc6b428213e4ee272e74dd06dd1c71c2a8e8 100644 (file)
@@ -142,9 +142,9 @@ public abstract class NhcThermostat {
     }
 
     /**
-     * Get the id of the thermostat.
+     * Get id of the thermostat.
      *
-     * @return the id
+     * @return id
      */
     public String getId() {
         return id;
@@ -160,7 +160,16 @@ public abstract class NhcThermostat {
     }
 
     /**
-     * Get location name of action.
+     * Set name of thermostat.
+     *
+     * @param name thermostat name
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Get location name of thermostat.
      *
      * @return location name
      */
@@ -168,6 +177,15 @@ public abstract class NhcThermostat {
         return location;
     }
 
+    /**
+     * Set location name of thermostat.
+     *
+     * @param location thermostat location name
+     */
+    public void setLocation(@Nullable String location) {
+        this.location = location;
+    }
+
     /**
      * Get measured temperature.
      *
index 45d3cdbb0778862f894d0f6441b97f0d9df2d043..1113efe8fb3b6ecb7438e7d4fb5e05e2035c2f80 100644 (file)
@@ -16,9 +16,15 @@ import java.io.IOException;
 import java.net.DatagramPacket;
 import java.net.DatagramSocket;
 import java.net.InetAddress;
+import java.net.SocketTimeoutException;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.core.util.HexUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -43,13 +49,13 @@ public final class NikoHomeControlDiscover {
 
     private final Logger logger = LoggerFactory.getLogger(NikoHomeControlDiscover.class);
 
-    private InetAddress addr;
-    private String nhcBridgeId = "";
-    private boolean isNhcII;
+    private List<String> nhcBridgeIds = new ArrayList<>();
+    private Map<String, InetAddress> addr = new HashMap<>();
+    private Map<String, Boolean> isNhcII = new HashMap<>();
 
     /**
-     * Discover a Niko Home Control IP interface by broadcasting UDP packet 0x44 to port 10000. The IP interface will
-     * reply. The address of the IP interface is than derived from that response.
+     * Discover the list of Niko Home Control IP interfaces by broadcasting UDP packet 0x44 to port 10000. The IP
+     * interface will reply. The address of the IP interface is than derived from that response.
      *
      * @param broadcast Broadcast address of the network
      * @throws IOException
@@ -68,33 +74,37 @@ public final class NikoHomeControlDiscover {
             datagramSocket.setBroadcast(true);
             datagramSocket.setSoTimeout(500);
             datagramSocket.send(discoveryPacket);
-            while (true) {
-                datagramSocket.receive(packet);
-                logger.trace("bridge discovery response {}",
-                        HexUtils.bytesToHex(Arrays.copyOf(packet.getData(), packet.getLength())));
-                if (isNhc(packet)) {
-                    break;
+            try {
+                while (true) {
+                    datagramSocket.receive(packet);
+                    logger.trace("bridge discovery response {}",
+                            HexUtils.bytesToHex(Arrays.copyOf(packet.getData(), packet.getLength())));
+                    if (isNhcController(packet)) {
+                        String bridgeId = setNhcBridgeId(packet);
+                        setIsNhcII(bridgeId, packet);
+                        setAddr(bridgeId, packet);
+                        logger.debug("IP address is {}, unique ID is {}", addr, bridgeId);
+                    }
                 }
+            } catch (SocketTimeoutException e) {
+                // all received, continue
             }
-            addr = packet.getAddress();
-            setNhcBridgeId(packet);
-            setIsNhcII(packet);
-            logger.debug("IP address is {}, unique ID is {}", addr, nhcBridgeId);
         }
     }
 
     /**
-     * @return the addr
+     * @return the discovered nhcBridgeIds
      */
-    public InetAddress getAddr() {
-        return addr;
+    public List<String> getNhcBridgeIds() {
+        return nhcBridgeIds;
     }
 
     /**
-     * @return the nhcBridgeId
+     * @param bridgeId discovered bridgeId
+     * @return the addr, null if not in the list of discovered bridgeId's
      */
-    public String getNhcBridgeId() {
-        return nhcBridgeId;
+    public @Nullable InetAddress getAddr(String bridgeId) {
+        return addr.get(bridgeId);
     }
 
     /**
@@ -103,9 +113,15 @@ public final class NikoHomeControlDiscover {
      * @param packet
      * @return true if packet is from a Niko Home Control controller
      */
-    private boolean isNhc(DatagramPacket packet) {
+    private boolean isNhcController(DatagramPacket packet) {
         byte[] packetData = packet.getData();
-        return ((packet.getLength() > 2) && (packetData[0] == 0x44));
+        boolean isNhc = (packet.getLength() > 2) && (packetData[0] == 0x44);
+        // filter response from Gen1 touchscreens
+        boolean isController = isNhc && (packetData[1] == 0x3b) || (packetData[1] == 0x0c) || (packetData[1] == 0x0e);
+        if (!isController) {
+            logger.trace("not a NHC controller");
+        }
+        return isController;
     }
 
     /**
@@ -113,7 +129,7 @@ public final class NikoHomeControlDiscover {
      *
      * @param packet
      */
-    private void setNhcBridgeId(DatagramPacket packet) {
+    private String setNhcBridgeId(DatagramPacket packet) {
         byte[] packetData = packet.getData();
         int packetLength = packet.getLength();
         packetLength = packetLength > 6 ? 6 : packetLength;
@@ -121,31 +137,45 @@ public final class NikoHomeControlDiscover {
         for (int i = 0; i < packetLength; i++) {
             sb.append(String.format("%02x", packetData[i]));
         }
-        nhcBridgeId = sb.toString();
+        String bridgeId = sb.toString();
+        nhcBridgeIds.add(bridgeId);
+        return bridgeId;
     }
 
     /**
      * Checks if this is a NHC II Connected Controller
      *
+     * @param bridgeId
      * @param packet
      */
-    private void setIsNhcII(DatagramPacket packet) {
+    private void setIsNhcII(String bridgeId, DatagramPacket packet) {
         byte[] packetData = packet.getData();
         int packetLength = packet.getLength();
         // The 16th byte in the packet is 2 for a NHC II Connected Controller
         if ((packetLength >= 16) && (packetData[15] >= 2)) {
-            isNhcII = true;
+            isNhcII.put(bridgeId, true);
         } else {
-            isNhcII = false;
+            isNhcII.put(bridgeId, false);
         }
     }
 
+    /**
+     * Sets the IP address retrieved from the packet response
+     *
+     * @param bridgeId
+     * @param packet
+     */
+    private void setAddr(String bridgeId, DatagramPacket packet) {
+        addr.put(bridgeId, packet.getAddress());
+    }
+
     /**
      * Test if the installation is a Niko Home Control II installation
      *
+     * @param bridgeId
      * @return true if this is a Niko Home Control II installation
      */
-    public boolean isNhcII() {
-        return isNhcII;
+    public boolean isNhcII(String bridgeId) {
+        return isNhcII.getOrDefault(bridgeId, false);
     }
 }
index f37a04da055936baba0a0ff58dd131833ecc4727..d66b64a9141c239232486565ba19b46c68f35374 100644 (file)
@@ -364,38 +364,38 @@ public class NikoHomeControlCommunication1 extends NikoHomeControlCommunication
             String value3 = action.get("value3");
             int openTime = ((value3 == null) || value3.isEmpty() ? 0 : Integer.parseInt(value3));
 
+            String name = action.get("name");
+            if (name == null) {
+                logger.debug("name not found in action {}", action);
+                continue;
+            }
+            String type = Optional.ofNullable(action.get("type")).orElse("");
+            ActionType actionType = ActionType.GENERIC;
+            switch (type) {
+                case "0":
+                    actionType = ActionType.TRIGGER;
+                    break;
+                case "1":
+                    actionType = ActionType.RELAY;
+                    break;
+                case "2":
+                    actionType = ActionType.DIMMER;
+                    break;
+                case "4":
+                case "5":
+                    actionType = ActionType.ROLLERSHUTTER;
+                    break;
+                default:
+                    logger.debug("unknown action type {} for action {}", type, id);
+                    continue;
+            }
+            String locationId = action.get("location");
+            String location = "";
+            if (locationId != null && !locationId.isEmpty()) {
+                location = locations.getOrDefault(locationId, new NhcLocation1("")).getName();
+            }
             if (!actions.containsKey(id)) {
                 // Initial instantiation of NhcAction class for action object
-                String name = action.get("name");
-                if (name == null) {
-                    logger.debug("name not found in action {}", action);
-                    continue;
-                }
-                String type = Optional.ofNullable(action.get("type")).orElse("");
-                ActionType actionType = ActionType.GENERIC;
-                switch (type) {
-                    case "0":
-                        actionType = ActionType.TRIGGER;
-                        break;
-                    case "1":
-                        actionType = ActionType.RELAY;
-                        break;
-                    case "2":
-                        actionType = ActionType.DIMMER;
-                        break;
-                    case "4":
-                    case "5":
-                        actionType = ActionType.ROLLERSHUTTER;
-                        break;
-                    default:
-                        logger.debug("unknown action type {} for action {}", type, id);
-                        continue;
-                }
-                String locationId = action.get("location");
-                String location = "";
-                if (locationId != null && !locationId.isEmpty()) {
-                    location = locations.getOrDefault(locationId, new NhcLocation1("")).getName();
-                }
                 NhcAction nhcAction = new NhcAction1(id, name, actionType, location, this, scheduler);
                 if (actionType == ActionType.ROLLERSHUTTER) {
                     nhcAction.setShutterTimes(openTime, closeTime);
@@ -403,11 +403,13 @@ public class NikoHomeControlCommunication1 extends NikoHomeControlCommunication
                 nhcAction.setState(state);
                 actions.put(id, nhcAction);
             } else {
-                // Action object already exists, so only update state.
+                // Action object already exists, so only update state, name and location.
                 // If we would re-instantiate action, we would lose pointer back from action to thing handler that was
                 // set in thing handler initialize().
                 NhcAction nhcAction = actions.get(id);
                 if (nhcAction != null) {
+                    nhcAction.setName(name);
+                    nhcAction.setLocation(location);
                     nhcAction.setState(state);
                 }
             }
@@ -452,23 +454,25 @@ public class NikoHomeControlCommunication1 extends NikoHomeControlCommunication
                 // measured
                 int demand = (mode != 3) ? (setpoint > measured ? 1 : (setpoint < measured ? -1 : 0)) : 0;
 
+                String name = thermostat.get("name");
+                String locationId = thermostat.get("location");
+                NhcLocation1 nhcLocation = null;
+                if (!((locationId == null) || locationId.isEmpty())) {
+                    nhcLocation = locations.get(locationId);
+                }
+                String location = (nhcLocation != null) ? nhcLocation.getName() : null;
                 NhcThermostat t = thermostats.computeIfAbsent(id, i -> {
                     // Initial instantiation of NhcThermostat class for thermostat object
-                    String name = thermostat.get("name");
-                    String locationId = thermostat.get("location");
-                    String location = "";
-                    if (!((locationId == null) || locationId.isEmpty())) {
-                        NhcLocation1 nhcLocation = locations.get(locationId);
-                        if (nhcLocation != null) {
-                            location = nhcLocation.getName();
-                        }
-                    }
                     if (name != null) {
                         return new NhcThermostat1(i, name, location, this);
                     }
                     throw new IllegalArgumentException();
                 });
                 if (t != null) {
+                    if (name != null) {
+                        t.setName(name);
+                    }
+                    t.setLocation(location);
                     t.updateState(measured, setpoint, mode, overrule, overruletime, ecosave, demand);
                 }
             } catch (IllegalArgumentException e) {
index 875b2885c9bf32e7ddef9a8780a7feb0fdd9bbe6..f0478fcb0a6c7e0ce54c847ccf6ab36a588714a1 100644 (file)
@@ -35,14 +35,16 @@ public class NhcAction2 extends NhcAction {
     private final Logger logger = LoggerFactory.getLogger(NhcAction2.class);
 
     private volatile boolean booleanState;
-    private String model;
-    private String technology;
+    private String deviceType;
+    private String deviceTechnology;
+    private String deviceModel;
 
-    NhcAction2(String id, String name, String model, String technology, ActionType type, @Nullable String location,
-            NikoHomeControlCommunication nhcComm) {
+    NhcAction2(String id, String name, String deviceType, String deviceTechnology, String deviceModel,
+            @Nullable String location, ActionType type, NikoHomeControlCommunication nhcComm) {
         super(id, name, type, location, nhcComm);
-        this.model = model;
-        this.technology = technology;
+        this.deviceType = deviceType;
+        this.deviceTechnology = deviceTechnology;
+        this.deviceModel = deviceModel;
     }
 
     /**
@@ -120,7 +122,7 @@ public class NhcAction2 extends NhcAction {
         logger.debug("execute action {} of type {} for {}", command, type, id);
 
         String cmd;
-        if ("flag".equals(model)) {
+        if ("flag".equals(deviceModel)) {
             cmd = NHCON.equals(command) ? NHCTRUE : NHCFALSE;
         } else {
             cmd = command;
@@ -130,16 +132,23 @@ public class NhcAction2 extends NhcAction {
     }
 
     /**
-     * @return model as returned from Niko Home Control
+     * @return type as returned from Niko Home Control
      */
-    public String getModel() {
-        return model;
+    public String getDeviceType() {
+        return deviceType;
     }
 
     /**
      * @return technology as returned from Niko Home Control
      */
-    public String getTechnology() {
-        return technology;
+    public String getDeviceTechnology() {
+        return deviceTechnology;
+    }
+
+    /**
+     * @return model as returned from Niko Home Control
+     */
+    public String getDeviceModel() {
+        return deviceModel;
     }
 }
index fc6a2948e78f0a97033bcd4fcec1df34c54c305f..c708b56c086fccb6e19ad120bb2730083293567e 100644 (file)
@@ -76,6 +76,18 @@ class NhcDevice2 {
         @Nullable
         String electricalPower;
         @Nullable
+        String electricalPowerToGrid;
+        @Nullable
+        String electricalPowerFromGrid;
+        @Nullable
+        String electricalPowerProduction;
+        @Nullable
+        String electricalPowerSelfConsumption;
+        @Nullable
+        String electricalPowerConsumption;
+        @Nullable
+        String electricalPowerProductionThresholdExceeded;
+        @Nullable
         String reportInstantUsage;
         // fields for access control
         @Nullable
index 9c8d194d1d8fa32f5733527def59159087242ca0..2c9401373a88d8c2d2128c65ddfa828b1ad52055 100644 (file)
@@ -34,14 +34,16 @@ public class NhcEnergyMeter2 extends NhcEnergyMeter {
     private ScheduledExecutorService scheduler;
     private volatile @Nullable ScheduledFuture<?> restartTimer;
 
-    private String model;
-    private String technology;
+    private String deviceType;
+    private String deviceTechnology;
+    private String deviceModel;
 
-    protected NhcEnergyMeter2(String id, String name, String model, String technology,
-            NikoHomeControlCommunication nhcComm, ScheduledExecutorService scheduler) {
-        super(id, name, nhcComm);
-        this.model = model;
-        this.technology = technology;
+    protected NhcEnergyMeter2(String id, String name, String deviceType, String deviceTechnology, String deviceModel,
+            @Nullable String location, NikoHomeControlCommunication nhcComm, ScheduledExecutorService scheduler) {
+        super(id, name, location, nhcComm);
+        this.deviceType = deviceType;
+        this.deviceTechnology = deviceTechnology;
+        this.deviceModel = deviceModel;
 
         this.scheduler = scheduler;
     }
@@ -75,16 +77,23 @@ public class NhcEnergyMeter2 extends NhcEnergyMeter {
     }
 
     /**
-     * @return model as returned from Niko Home Control
+     * @return type as returned from Niko Home Control
      */
-    public String getModel() {
-        return model;
+    public String getDeviceType() {
+        return deviceType;
     }
 
     /**
      * @return technology as returned from Niko Home Control
      */
-    public String getTechnology() {
-        return technology;
+    public String getDeviceTechnology() {
+        return deviceTechnology;
+    }
+
+    /**
+     * @return model as returned from Niko Home Control
+     */
+    public String getDeviceModel() {
+        return deviceModel;
     }
 }
index 54a9fb013869b5d19903124ee841e66c9b5b46de..40da2d9169438ca156829a980bfe0c94a3908bc5 100644 (file)
@@ -33,14 +33,16 @@ public class NhcThermostat2 extends NhcThermostat {
 
     private final Logger logger = LoggerFactory.getLogger(NhcThermostat2.class);
 
-    private String model;
-    private String technology;
+    private String deviceType;
+    private String deviceTechnology;
+    private String deviceModel;
 
-    protected NhcThermostat2(String id, String name, String model, String technology, @Nullable String location,
-            NikoHomeControlCommunication nhcComm) {
+    protected NhcThermostat2(String id, String name, String deviceType, String deviceTechnology, String deviceModel,
+            @Nullable String location, NikoHomeControlCommunication nhcComm) {
         super(id, name, location, nhcComm);
-        this.model = model;
-        this.technology = technology;
+        this.deviceType = deviceType;
+        this.deviceTechnology = deviceTechnology;
+        this.deviceModel = deviceModel;
     }
 
     @Override
@@ -59,16 +61,23 @@ public class NhcThermostat2 extends NhcThermostat {
     }
 
     /**
-     * @return model as returned from Niko Home Control
+     * @return type as returned from Niko Home Control
      */
-    public String getModel() {
-        return model;
+    public String getDeviceType() {
+        return deviceType;
     }
 
     /**
      * @return technology as returned from Niko Home Control
      */
-    public String getTechnology() {
-        return technology;
+    public String getDeviceTechnology() {
+        return deviceTechnology;
+    }
+
+    /**
+     * @return model as returned from Niko Home Control
+     */
+    public String getDeviceModel() {
+        return deviceModel;
     }
 }
index 13693be37fb83d1021d92def994e810822bbcf9a..d46af6f57a7b9fd29143433e76c12630a53b4108 100644 (file)
@@ -364,63 +364,77 @@ public class NikoHomeControlCommunication2 extends NikoHomeControlCommunication
         }
 
         if ("action".equals(device.type) || "virtual".equals(device.type)) {
-            if (!actions.containsKey(device.uuid)) {
-                logger.debug("adding action device {}, {}", device.uuid, device.name);
-
-                ActionType actionType;
-                switch (device.model) {
-                    case "generic":
-                    case "pir":
-                    case "simulation":
-                    case "comfort":
-                    case "alarms":
-                    case "alloff":
-                    case "overallcomfort":
-                    case "garagedoor":
-                        actionType = ActionType.TRIGGER;
-                        break;
-                    case "light":
-                    case "socket":
-                    case "switched-generic":
-                    case "switched-fan":
-                    case "flag":
-                        actionType = ActionType.RELAY;
-                        break;
-                    case "dimmer":
-                        actionType = ActionType.DIMMER;
-                        break;
-                    case "rolldownshutter":
-                    case "sunblind":
-                    case "venetianblind":
-                    case "gate":
-                        actionType = ActionType.ROLLERSHUTTER;
-                        break;
-                    default:
-                        actionType = ActionType.GENERIC;
-                        logger.debug("device model {} not recognised, default to GENERIC action", device.model);
-                }
+            ActionType actionType;
+            switch (device.model) {
+                case "generic":
+                case "pir":
+                case "simulation":
+                case "comfort":
+                case "alarms":
+                case "alloff":
+                case "overallcomfort":
+                case "garagedoor":
+                    actionType = ActionType.TRIGGER;
+                    break;
+                case "light":
+                case "socket":
+                case "switched-generic":
+                case "switched-fan":
+                case "flag":
+                    actionType = ActionType.RELAY;
+                    break;
+                case "dimmer":
+                    actionType = ActionType.DIMMER;
+                    break;
+                case "rolldownshutter":
+                case "sunblind":
+                case "venetianblind":
+                case "gate":
+                    actionType = ActionType.ROLLERSHUTTER;
+                    break;
+                default:
+                    actionType = ActionType.GENERIC;
+                    logger.debug("device type {} and model {} not recognised for {}, {}, ignoring", device.type,
+                            device.model, device.uuid, device.name);
+                    return;
+            }
 
-                NhcAction2 nhcAction = new NhcAction2(device.uuid, device.name, device.model, device.technology,
-                        actionType, location, this);
-                actions.put(device.uuid, nhcAction);
+            NhcAction nhcAction = actions.get(device.uuid);
+            if (nhcAction != null) {
+                // update name and location so discovery will see updated name and location
+                nhcAction.setName(device.name);
+                nhcAction.setLocation(location);
+            } else {
+                logger.debug("adding action device {} model {}, {}", device.uuid, device.model, device.name);
+                nhcAction = new NhcAction2(device.uuid, device.name, device.type, device.technology, device.model,
+                        location, actionType, this);
             }
+            actions.put(device.uuid, nhcAction);
         } else if ("thermostat".equals(device.type)) {
-            if (!thermostats.containsKey(device.uuid)) {
-                logger.debug("adding thermostat device {}, {}", device.uuid, device.name);
-
-                NhcThermostat2 nhcThermostat = new NhcThermostat2(device.uuid, device.name, device.model,
-                        device.technology, location, this);
-                thermostats.put(device.uuid, nhcThermostat);
+            NhcThermostat nhcThermostat = thermostats.get(device.uuid);
+            if (nhcThermostat != null) {
+                nhcThermostat.setName(device.name);
+                nhcThermostat.setLocation(location);
+            } else {
+                logger.debug("adding thermostat device {} model {}, {}", device.uuid, device.model, device.name);
+                nhcThermostat = new NhcThermostat2(device.uuid, device.name, device.type, device.technology,
+                        device.model, location, this);
             }
-        } else if ("centralmeter".equals(device.type)) {
-            if (!energyMeters.containsKey(device.uuid)) {
-                logger.debug("adding centralmeter device {}, {}", device.uuid, device.name);
-                NhcEnergyMeter2 nhcEnergyMeter = new NhcEnergyMeter2(device.uuid, device.name, device.model,
-                        device.technology, this, scheduler);
-                energyMeters.put(device.uuid, nhcEnergyMeter);
+            thermostats.put(device.uuid, nhcThermostat);
+        } else if ("centralmeter".equals(device.type) || "energyhome".equals(device.type)) {
+            NhcEnergyMeter nhcEnergyMeter = energyMeters.get(device.uuid);
+            if (nhcEnergyMeter != null) {
+                nhcEnergyMeter.setName(device.name);
+                nhcEnergyMeter.setLocation(location);
+            } else {
+                logger.debug("adding energy meter device {} model {}, {}", device.uuid, device.model, device.name);
+                nhcEnergyMeter = new NhcEnergyMeter2(device.uuid, device.name, device.type, device.technology,
+                        device.model, location, this, scheduler);
             }
+            energyMeters.put(device.uuid, nhcEnergyMeter);
         } else {
-            logger.debug("device type {} not supported for {}, {}", device.type, device.uuid, device.name);
+            logger.debug("device type {} and model {} not supported for {}, {}", device.type, device.model, device.uuid,
+                    device.name);
         }
     }
 
@@ -580,18 +594,23 @@ public class NikoHomeControlCommunication2 extends NikoHomeControlCommunication
     }
 
     private void updateEnergyMeterState(NhcEnergyMeter2 energyMeter, List<NhcProperty> deviceProperties) {
-        deviceProperties.stream().map(p -> p.electricalPower).filter(Objects::nonNull).findFirst()
-                .ifPresent(electricalPower -> {
-                    try {
-                        // Sometimes API sends a fractional part, although API should only send whole units in W,
-                        // therefore drop fractional part
-                        energyMeter.setPower((int) Double.parseDouble(electricalPower));
-                        logger.trace("setting energy meter {} power to {}", energyMeter.getId(), electricalPower);
-                    } catch (NumberFormatException e) {
-                        energyMeter.setPower(null);
-                        logger.trace("received empty energy meter {} power reading", energyMeter.getId());
-                    }
-                });
+        try {
+            Optional<Integer> electricalPower = deviceProperties.stream().map(p -> p.electricalPower)
+                    .map(s -> (!((s == null) || s.isEmpty())) ? Math.round(Float.parseFloat(s)) : null)
+                    .filter(Objects::nonNull).findFirst();
+            Optional<Integer> powerFromGrid = deviceProperties.stream().map(p -> p.electricalPowerFromGrid)
+                    .map(s -> (!((s == null) || s.isEmpty())) ? Math.round(Float.parseFloat(s)) : null)
+                    .filter(Objects::nonNull).findFirst();
+            Optional<Integer> powerToGrid = deviceProperties.stream().map(p -> p.electricalPowerToGrid)
+                    .map(s -> (!((s == null) || s.isEmpty())) ? Math.round(Float.parseFloat(s)) : null)
+                    .filter(Objects::nonNull).findFirst();
+            int power = electricalPower.orElse(powerFromGrid.orElse(0) - powerToGrid.orElse(0));
+            logger.trace("setting energy meter {} power to {}", energyMeter.getId(), electricalPower);
+            energyMeter.setPower(power);
+        } catch (NumberFormatException e) {
+            energyMeter.setPower(null);
+            logger.trace("received empty energy meter {} power reading", energyMeter.getId());
+        }
     }
 
     @Override
@@ -876,7 +895,7 @@ public class NikoHomeControlCommunication2 extends NikoHomeControlCommunication
     @Override
     public void connectionStateChanged(MqttConnectionState state, @Nullable Throwable error) {
         if (error != null) {
-            logger.debug("Connection state: {}", state, error);
+            logger.debug("Connection state: {}, error", state, error);
             String message = error.getLocalizedMessage();
             message = (message != null) ? message : "@text/offline.communication-error";
             if (!MqttConnectionState.CONNECTING.equals(state)) {