]> git.basschouten.com Git - openhab-addons.git/commitdiff
[velux] fix bugs with Somfy devices, and switch devices (#9245)
authorAndrew Fiddian-Green <software@whitebear.ch>
Tue, 8 Dec 2020 17:20:14 +0000 (17:20 +0000)
committerGitHub <noreply@github.com>
Tue, 8 Dec 2020 17:20:14 +0000 (09:20 -0800)
* [velux] add data type to config params in readme
* [velux] eliminate mvn warning
* [velux] fix Somfy bugs: uniqueindex = serial number or name
* [velux] fix inconsistent switch state logic
* [velux] cosmetics on BRIDGE_THING_TYPE_UID

Signed-off-by: Andrew Fiddian-Green <software@whitebear.ch>
bundles/org.openhab.binding.velux/README.md
bundles/org.openhab.binding.velux/src/main/java/org/openhab/binding/velux/internal/VeluxBindingConstants.java
bundles/org.openhab.binding.velux/src/main/java/org/openhab/binding/velux/internal/handler/ChannelActuatorPosition.java
bundles/org.openhab.binding.velux/src/main/java/org/openhab/binding/velux/internal/handler/VeluxBridgeHandler.java
bundles/org.openhab.binding.velux/src/main/java/org/openhab/binding/velux/internal/handler/utils/Thing2VeluxActuator.java
bundles/org.openhab.binding.velux/src/main/java/org/openhab/binding/velux/internal/things/VeluxExistingProducts.java
bundles/org.openhab.binding.velux/src/main/java/org/openhab/binding/velux/internal/things/VeluxProduct.java
bundles/org.openhab.binding.velux/src/main/resources/OH-INF/config/config.xml

index fc08919fc35210323f5a8a9f41fc95948d2fe6e3..ec0ced2768172a145451ce0f97766a82d97ef1f7 100644 (file)
@@ -82,17 +82,17 @@ These types of Thing only supported in the Velux Bridge in API version two or hi
 These types of Thing are configured by means of their serial number in the hub.
 In addition there are some optional Configuration Parameters.
 
-| Configuration Parameter | Default                | Required | Description                                                       |
-|-------------------------|------------------------|:--------:|-------------------------------------------------------------------|
-| serial                  |                        |   Yes    | Serial number of the io-homecontrol device in the hub.            |
-| name                    |                        |    No    | (Optional) name of the io-homecontrol device in the hub.          |
-| inverted                | false                  |    No    | (Optional) the position is inverted (i.e. 0% translates to 100%). |
+| Configuration Parameter | Default | Type    | Required | Description                                                                            |
+|-------------------------|---------|---------|:--------:|----------------------------------------------------------------------------------------|
+| serial                  |         | custom  |   Yes    | Serial number of the device in the hub (custom format 00:00:00:00:00:00:00:00)         |
+| name                    |         | text    |    No    | Name of the device in the hub.                                                         |
+| inverted                | false   | boolean |    No    | The `position` and `state` (if available) are inverted (i.e. 0% <-> 100%, OFF <-> ON). |
 
 Notes:
 
 1. To enable a complete inversion of all parameter values (i.e. for Velux windows), use the property `inverted` or add a trailing star to the eight-byte serial number. For an example, see below at item `Velux DG Window Bathroom`.
 
-2. Somfy devices do not provide a valid serial number to the Velux KLF200 gateway. The bridge reports a registration of the serial number 00:00:00:00:00:00:00:00. Therefore the binding implements a fallback to allow an item specification with a actuator `name` instead of actuator serial number whenever such an invalid serial number occurs. For an example, see below at item `Velux OG Somfy Shutter`.
+2. Somfy devices do not provide a valid serial number to the Velux KLF200 gateway. In this case you should enter the default `serial` number 00:00:00:00:00:00:00:00, and in addition enter the `name` parameter; this is the name that you gave to the actuator when you first registered it in the KLF200 Bridge. For an example, see below at item `Velux OG Somfy Shutter`.
 
 ### Thing Configuration for "scene"
 
@@ -100,10 +100,10 @@ The Velux Bridge in API version one (firmware version 0.1.1.*) allows activating
 So besides the bridge, only one real Thing type exists, namely "scene".
 This type of Thing is configured by means of its scene name in the hub.
 
-| Configuration Parameter | Default                | Required | Description                                                           |
-|-------------------------|------------------------|:--------:|-----------------------------------------------------------------------|
-| sceneName               |                        |   Yes    | Name of the scene in the hub.                                         |
-| velocity                |                        |   No     | The speed at which the scene will be executed (deafult, silent, fast) |
+| Configuration Parameter | Default   | Type | Required | Description                                                                 |
+|-------------------------|-----------|------|:--------:|-----------------------------------------------------------------------------|
+| sceneName               |           | text |   Yes    | Name of the scene in the hub.                                               |
+| velocity                | 'default' | text |    No    | The speed at which the scene will be executed ('default', 'silent', 'fast') |
 
 ### Thing Configuration for "vshutter"
 
@@ -112,10 +112,10 @@ So besides the bridge, this binding provides a virtual rollershutter Thing consi
 Therefore the respective Item definition contains multiple pairs of rollershutter levels each followed by a scene name.
 The virtual shutter Thing must be configured with pairs of level (0..10%) combined with the appropriate scene names (text) as follows.
 
-| Configuration Parameter | Default                | Required | Description                                               |
-|-------------------------|------------------------|:--------:|-----------------------------------------------------------|
-| sceneLevels             |                        |   Yes    | <Level1>,<Scene1>,<Level2>,<Scene2>,....                  |
-| currentLevel            | 0                      |    No    | Inverts any device values.                                |
+| Configuration Parameter | Default | Type    | Required | Description                             |
+|-------------------------|---------|---------|:--------:|-----------------------------------------|
+| sceneLevels             |         | text    |   Yes    | {Level1},{Scene1},{Level2},{Scene2},..  |
+| currentLevel            | 0       | integer |    No    | Inverts any device values (0..100).     |
 
 ## Supported Channels for Thing Types
 
index 739be2184638ee4371039e34a0366e832484710e..3f7012b99715e3a3e79819209f26c2d0ea31c951 100644 (file)
@@ -153,4 +153,6 @@ public class VeluxBindingConstants {
 
     public static final String UNKNOWN_THING_TYPE_ID = "FAILED";
     public static final String UNKNOWN_IP_ADDRESS = "xxx.xxx.xxx.xxx";
+
+    public static final String BRIDGE_THING_TYPE_UID = THING_TYPE_BRIDGE.toString();
 }
index c9b83f0633aa1cb0e3fee7fc737bf5e96e73d48d..f9af1bc0c0563196251ef9081b370b1a79f69e07 100644 (file)
@@ -12,7 +12,7 @@
  */
 package org.openhab.binding.velux.internal.handler;
 
-import static org.openhab.binding.velux.internal.VeluxBindingConstants.CHANNEL_ACTUATOR_POSITION;
+import static org.openhab.binding.velux.internal.VeluxBindingConstants.*;
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.jdt.annotation.Nullable;
@@ -82,6 +82,10 @@ final class ChannelActuatorPosition extends ChannelHandlerTemplate {
                 LOGGER.trace("handleRefresh(): there are some existing products.");
             }
             Thing2VeluxActuator veluxActuator = thisBridgeHandler.channel2VeluxActuator.get(channelUID);
+            if (veluxActuator == null || !veluxActuator.isKnown()) {
+                LOGGER.warn("handleRefresh(): unknown actuator.");
+                break;
+            }
             GetProduct bcp = thisBridgeHandler.thisBridge.bridgeAPI().getProduct();
             if (bcp == null) {
                 LOGGER.trace("handleRefresh(): aborting processing as handler is null.");
@@ -93,10 +97,16 @@ final class ChannelActuatorPosition extends ChannelHandlerTemplate {
                     VeluxProduct product = bcp.getProduct();
                     VeluxProductPosition position = new VeluxProductPosition(product.getDisplayPosition());
                     if (position.isValid()) {
-                        PercentType posPercent = position.getPositionAsPercentType(veluxActuator.isInverted());
-                        LOGGER.trace("handleRefresh(): position of actuator is {}%.", posPercent);
-                        newState = posPercent;
-                        break;
+                        if (CHANNEL_ACTUATOR_POSITION.equals(channelId)) {
+                            newState = position.getPositionAsPercentType(veluxActuator.isInverted());
+                            LOGGER.trace("handleRefresh(): position of actuator is {}%.", newState);
+                            break;
+                        } else if (CHANNEL_ACTUATOR_STATE.equals(channelId)) {
+                            newState = OnOffType.from(
+                                    position.getPositionAsPercentType(veluxActuator.isInverted()).intValue() > 50);
+                            LOGGER.trace("handleRefresh(): state of actuator is {}.", newState);
+                            break;
+                        }
                     }
                     LOGGER.trace("handleRefresh(): position of actuator is 'UNDEFINED'.");
                     newState = UnDefType.UNDEF;
@@ -124,55 +134,49 @@ final class ChannelActuatorPosition extends ChannelHandlerTemplate {
         LOGGER.debug("handleCommand({},{},{},{}) called.", channelUID, channelId, command, thisBridgeHandler);
         Command newValue = null;
         do { // just for common exit
-            assert thisBridgeHandler.bridgeParameters.actuators != null : "VeluxBridgeHandler.bridgeParameters.actuators not initialized.";
             if (thisBridgeHandler.bridgeParameters.actuators.autoRefresh(thisBridgeHandler.thisBridge)) {
                 LOGGER.trace("handleCommand(): there are some existing products.");
             }
             Thing2VeluxActuator veluxActuator = thisBridgeHandler.channel2VeluxActuator.get(channelUID);
+            if (veluxActuator == null || !veluxActuator.isKnown()) {
+                LOGGER.warn("handleRefresh(): unknown actuator.");
+                break;
+            }
             VeluxProductPosition targetLevel = VeluxProductPosition.UNKNOWN;
-            if (channelId.equals(CHANNEL_ACTUATOR_POSITION)) {
-                if ((command instanceof UpDownType) && (command == UpDownType.UP)) {
-                    LOGGER.trace("handleCommand(): found UP command.");
-                    targetLevel = veluxActuator.isInverted() ? new VeluxProductPosition(PercentType.HUNDRED)
-                            : new VeluxProductPosition(PercentType.ZERO);
-                } else if ((command instanceof UpDownType) && (command == UpDownType.DOWN)) {
-                    LOGGER.trace("handleCommand(): found DOWN command.");
-                    targetLevel = veluxActuator.isInverted() ? new VeluxProductPosition(PercentType.ZERO)
+            if (CHANNEL_ACTUATOR_POSITION.equals(channelId)) {
+                if (command instanceof UpDownType) {
+                    LOGGER.trace("handleCommand(): found UpDownType.{} command.", command);
+                    targetLevel = UpDownType.UP.equals(command) ^ veluxActuator.isInverted()
+                            ? new VeluxProductPosition(PercentType.ZERO)
                             : new VeluxProductPosition(PercentType.HUNDRED);
-                } else if ((command instanceof StopMoveType) && (command == StopMoveType.STOP)) {
-                    LOGGER.trace("handleCommand(): found STOP command.");
-                    targetLevel = new VeluxProductPosition();
+                } else if (command instanceof StopMoveType) {
+                    LOGGER.trace("handleCommand(): found StopMoveType.{} command.", command);
+                    targetLevel = StopMoveType.STOP.equals(command) ? new VeluxProductPosition() : targetLevel;
                 } else if (command instanceof PercentType) {
-                    LOGGER.trace("handleCommand(): found command of type PercentType.");
+                    LOGGER.trace("handleCommand(): found PercentType.{} command", command);
                     PercentType ptCommand = (PercentType) command;
                     if (veluxActuator.isInverted()) {
                         ptCommand = new PercentType(PercentType.HUNDRED.intValue() - ptCommand.intValue());
                     }
                     LOGGER.trace("handleCommand(): found command to set level to {}.", ptCommand);
                     targetLevel = new VeluxProductPosition(ptCommand);
-                } else {
-                    LOGGER.info("handleCommand({},{}): ignoring command.", channelUID.getAsString(), command);
-                    break;
                 }
-            } else {
-                if ((command instanceof OnOffType) && (command == OnOffType.ON)) {
-                    LOGGER.trace("handleCommand(): found ON command.");
-                    targetLevel = veluxActuator.isInverted() ? new VeluxProductPosition(PercentType.HUNDRED)
-                            : new VeluxProductPosition(PercentType.ZERO);
-                } else if ((command instanceof OnOffType) && (command == OnOffType.OFF)) {
-                    LOGGER.trace("handleCommand(): found OFF command.");
-                    targetLevel = veluxActuator.isInverted() ? new VeluxProductPosition(PercentType.ZERO)
+            } else if (CHANNEL_ACTUATOR_STATE.equals(channelId)) {
+                if (command instanceof OnOffType) {
+                    LOGGER.trace("handleCommand(): found OnOffType.{} command.", command);
+                    targetLevel = OnOffType.OFF.equals(command) ^ veluxActuator.isInverted()
+                            ? new VeluxProductPosition(PercentType.ZERO)
                             : new VeluxProductPosition(PercentType.HUNDRED);
-                } else {
-                    LOGGER.info("handleCommand({},{}): ignoring command.", channelUID.getAsString(), command);
-                    break;
                 }
             }
+            if (targetLevel == VeluxProductPosition.UNKNOWN) {
+                LOGGER.info("handleCommand({},{}): ignoring command.", channelUID.getAsString(), command);
+                break;
+            }
             LOGGER.debug("handleCommand(): sending command with target level {}.", targetLevel);
             new VeluxBridgeRunProductCommand().sendCommand(thisBridgeHandler.thisBridge,
                     veluxActuator.getProductBridgeIndex().toInt(), targetLevel);
             LOGGER.trace("handleCommand(): The new shutter level will be send through the home monitoring events.");
-
             if (thisBridgeHandler.bridgeParameters.actuators.autoRefresh(thisBridgeHandler.thisBridge)) {
                 LOGGER.trace("handleCommand(): position of actuators are updated.");
             }
index 0fe7f2efa1c6fd066d952ec4fac5b0fd5ec3063e..04f4898f6a607b17bdca56848d052360852f3496 100644 (file)
@@ -466,7 +466,7 @@ public class VeluxBridgeHandler extends ExtendedBaseBridgeHandler implements Vel
                     continue;
                 }
                 Thing2VeluxActuator actuator = channel2VeluxActuator.get(channelUID);
-                if (!actuator.isKnown()) {
+                if (actuator == null || !actuator.isKnown()) {
                     logger.trace("syncChannelsWithProducts(): channel {} not registered on bridge.", channelUID);
                     continue;
                 }
index f86cbbf0d101ab7a42a5854ddabcce7b0fb80dd3..916c21c628c435f46fe06506bab9fceaad5e703c 100644 (file)
 package org.openhab.binding.velux.internal.handler.utils;
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.binding.velux.internal.VeluxBindingConstants;
 import org.openhab.binding.velux.internal.VeluxBindingProperties;
 import org.openhab.binding.velux.internal.handler.VeluxBridgeHandler;
+import org.openhab.binding.velux.internal.things.VeluxExistingProducts;
 import org.openhab.binding.velux.internal.things.VeluxProduct;
 import org.openhab.binding.velux.internal.things.VeluxProduct.ProductBridgeIndex;
 import org.openhab.binding.velux.internal.things.VeluxProductSerialNo;
@@ -50,32 +52,60 @@ public class Thing2VeluxActuator {
     // Private
 
     private void mapThing2Velux() {
-        if (!ThingConfiguration.exists(bridgeHandler, channelUID,
-                VeluxBindingProperties.CONFIG_ACTUATOR_SERIALNUMBER)) {
-            logger.trace("mapThing2Velux(): aborting processing as {} is not set within {}.",
-                    VeluxBindingProperties.CONFIG_ACTUATOR_SERIALNUMBER, channelUID);
+        if (channelUID.toString().startsWith(VeluxBindingConstants.BRIDGE_THING_TYPE_UID)) {
+            logger.trace("mapThing2Velux(): channel {} is on a Bridge Thing, exiting.", channelUID);
             return;
         }
-        String actuatorSerial = (String) ThingConfiguration.getValue(bridgeHandler, channelUID,
-                VeluxBindingProperties.CONFIG_ACTUATOR_SERIALNUMBER);
-        logger.trace("mapThing2Velux(): found actuatorSerial={}.", actuatorSerial);
-
-        // Handle value inversion
-        boolean propertyInverted = false;
-        if (ThingConfiguration.exists(bridgeHandler, channelUID, VeluxBindingProperties.PROPERTY_ACTUATOR_INVERTED)) {
-            propertyInverted = (boolean) ThingConfiguration.getValue(bridgeHandler, channelUID,
-                    VeluxBindingProperties.PROPERTY_ACTUATOR_INVERTED);
+
+        // the uniqueIndex is the serial number (if valid)
+        String uniqueIndex = null;
+        boolean invert = false;
+        if (ThingConfiguration.exists(bridgeHandler, channelUID, VeluxBindingProperties.CONFIG_ACTUATOR_SERIALNUMBER)) {
+            String serial = (String) ThingConfiguration.getValue(bridgeHandler, channelUID,
+                    VeluxBindingProperties.CONFIG_ACTUATOR_SERIALNUMBER);
+            invert = VeluxProductSerialNo.indicatesRevertedValues(serial);
+            serial = VeluxProductSerialNo.cleaned(serial);
+            uniqueIndex = ("".equals(serial) || serial.equals(VeluxProductSerialNo.UNKNOWN)) ? null : serial;
+        }
+        logger.trace("mapThing2Velux(): in {} serialNumber={}.", channelUID, uniqueIndex);
+
+        // if serial number not valid, the uniqueIndex is name (if valid)
+        if (uniqueIndex == null) {
+            if (ThingConfiguration.exists(bridgeHandler, channelUID, VeluxBindingProperties.PROPERTY_ACTUATOR_NAME)) {
+                String name = (String) ThingConfiguration.getValue(bridgeHandler, channelUID,
+                        VeluxBindingProperties.PROPERTY_ACTUATOR_NAME);
+                uniqueIndex = ("".equals(name) || name.equals(VeluxBindingConstants.UNKNOWN)) ? null : name;
+            }
+            logger.trace("mapThing2Velux(): in {} name={}.", channelUID, uniqueIndex);
+        }
+
+        if (uniqueIndex == null) {
+            logger.warn("mapThing2Velux(): in {} cannot find a uniqueIndex, aborting.", channelUID);
+            return;
+        } else {
+            logger.trace("mapThing2Velux(): in {} uniqueIndex={}, proceeding.", channelUID, uniqueIndex);
+        }
+
+        // handle value inversion
+        if (!invert) {
+            if (ThingConfiguration.exists(bridgeHandler, channelUID,
+                    VeluxBindingProperties.PROPERTY_ACTUATOR_INVERTED)) {
+                invert = (boolean) ThingConfiguration.getValue(bridgeHandler, channelUID,
+                        VeluxBindingProperties.PROPERTY_ACTUATOR_INVERTED);
+            }
         }
-        isInverted = propertyInverted || VeluxProductSerialNo.indicatesRevertedValues(actuatorSerial);
-        logger.trace("mapThing2Velux(): found isInverted={}.", isInverted);
-        actuatorSerial = VeluxProductSerialNo.cleaned(actuatorSerial);
+        isInverted = invert;
+        logger.trace("mapThing2Velux(): in {} isInverted={}.", channelUID, isInverted);
 
-        if (!bridgeHandler.bridgeParameters.actuators.getChannel().existingProducts.isRegistered(actuatorSerial)) {
-            logger.warn("mapThing2Velux(): cannot work on unknown actuator with serial {}.", actuatorSerial);
+        VeluxExistingProducts existing = bridgeHandler.bridgeParameters.actuators.getChannel().existingProducts;
+
+        if (!existing.isRegistered(uniqueIndex)) {
+            logger.warn("mapThing2Velux(): actuator with uniqueIndex={} is not registered", uniqueIndex);
             return;
         }
-        logger.trace("mapThing2Velux(): fetching actuator for {}.", actuatorSerial);
-        thisProduct = bridgeHandler.bridgeParameters.actuators.getChannel().existingProducts.get(actuatorSerial);
+
+        logger.trace("mapThing2Velux(): fetching actuator for {}.", uniqueIndex);
+        thisProduct = existing.get(uniqueIndex);
         logger.debug("mapThing2Velux(): found actuator {}.", thisProduct);
         return;
     }
index 51c18f312541a373bff65a31cfe51bf6d4745ef7..592c379a943ee053160ecfe677084629143a6d47 100644 (file)
@@ -47,7 +47,7 @@ public class VeluxExistingProducts {
     // Type definitions, class-internal variables
 
     private Map<String, VeluxProduct> existingProductsByUniqueIndex;
-    private Map<Integer, String> bridgeIndexToSerialNumber;
+    private Map<Integer, String> bridgeIndexToUniqueIndex;
     private Map<String, VeluxProduct> modifiedProductsByUniqueIndex;
     private int memberCount;
 
@@ -61,7 +61,7 @@ public class VeluxExistingProducts {
     public VeluxExistingProducts() {
         logger.trace("VeluxExistingProducts(constructor) called.");
         existingProductsByUniqueIndex = new ConcurrentHashMap<>();
-        bridgeIndexToSerialNumber = new ConcurrentHashMap<>();
+        bridgeIndexToUniqueIndex = new ConcurrentHashMap<>();
         modifiedProductsByUniqueIndex = new ConcurrentHashMap<>();
         memberCount = 0;
         dirty = true;
@@ -70,24 +70,22 @@ public class VeluxExistingProducts {
 
     // Class access methods
 
-    public boolean isRegistered(String productUniqueIndexOrSerialNumber) {
-        logger.trace("isRegistered(String {}) returns {}.", productUniqueIndexOrSerialNumber,
-                existingProductsByUniqueIndex.containsKey(productUniqueIndexOrSerialNumber) ? "true" : "false");
-        return existingProductsByUniqueIndex.containsKey(productUniqueIndexOrSerialNumber);
+    public boolean isRegistered(String productUniqueIndex) {
+        boolean result = existingProductsByUniqueIndex.containsKey(productUniqueIndex);
+        logger.trace("isRegistered(String {}) returns {}.", productUniqueIndex, result);
+        return result;
     }
 
     public boolean isRegistered(VeluxProduct product) {
-        logger.trace("isRegistered(VeluxProduct {}) called.", product.toString());
-        if (product.isV2()) {
-            return isRegistered(product.getSerialNumber());
-        }
-        return isRegistered(product.getProductUniqueIndex());
+        boolean result = existingProductsByUniqueIndex.containsKey(product.getProductUniqueIndex());
+        logger.trace("isRegistered(VeluxProduct {}) returns {}.", product, result);
+        return result;
     }
 
     public boolean isRegistered(ProductBridgeIndex bridgeProductIndex) {
-        logger.trace("isRegisteredProductBridgeIndex {}) called.", bridgeProductIndex.toString());
-        String serialNumber = bridgeIndexToSerialNumber.get(bridgeProductIndex.toInt());
-        return serialNumber != null && isRegistered(serialNumber);
+        boolean result = bridgeIndexToUniqueIndex.containsKey(bridgeProductIndex.toInt());
+        logger.trace("isRegistered(ProductBridgeIndex {}) returns {}.", bridgeProductIndex, result);
+        return result;
     }
 
     public boolean register(VeluxProduct newProduct) {
@@ -97,12 +95,12 @@ public class VeluxExistingProducts {
         }
         logger.trace("register() registering new product {}.", newProduct);
 
-        String uniqueIndex = newProduct.isV2() ? newProduct.getSerialNumber() : newProduct.getProductUniqueIndex();
+        String uniqueIndex = newProduct.getProductUniqueIndex();
         logger.trace("register() registering by UniqueIndex {}", uniqueIndex);
         existingProductsByUniqueIndex.put(uniqueIndex, newProduct);
 
         logger.trace("register() registering by ProductBridgeIndex {}", newProduct.getBridgeProductIndex().toInt());
-        bridgeIndexToSerialNumber.put(newProduct.getBridgeProductIndex().toInt(), newProduct.getSerialNumber());
+        bridgeIndexToUniqueIndex.put(newProduct.getBridgeProductIndex().toInt(), uniqueIndex);
 
         logger.trace("register() registering set of modifications by UniqueIndex {}", uniqueIndex);
         modifiedProductsByUniqueIndex.put(uniqueIndex, newProduct);
@@ -125,8 +123,7 @@ public class VeluxExistingProducts {
         dirty |= thisProduct.setCurrentPosition(productPosition);
         dirty |= thisProduct.setTarget(productTarget);
         if (dirty) {
-            String uniqueIndex = thisProduct.isV2() ? thisProduct.getSerialNumber()
-                    : thisProduct.getProductUniqueIndex();
+            String uniqueIndex = thisProduct.getProductUniqueIndex();
             logger.trace("update(): updating by UniqueIndex {}.", uniqueIndex);
             existingProductsByUniqueIndex.replace(uniqueIndex, thisProduct);
             modifiedProductsByUniqueIndex.put(uniqueIndex, thisProduct);
@@ -141,21 +138,16 @@ public class VeluxExistingProducts {
                 currentProduct.getCurrentPosition(), currentProduct.getTarget());
     }
 
-    public VeluxProduct get(String productUniqueIndexOrSerialNumber) {
-        logger.trace("get({}) called.", productUniqueIndexOrSerialNumber);
-        if (!isRegistered(productUniqueIndexOrSerialNumber)) {
-            return VeluxProduct.UNKNOWN;
-        }
-        return existingProductsByUniqueIndex.getOrDefault(productUniqueIndexOrSerialNumber, VeluxProduct.UNKNOWN);
+    public VeluxProduct get(String productUniqueIndex) {
+        logger.trace("get({}) called.", productUniqueIndex);
+        return existingProductsByUniqueIndex.getOrDefault(productUniqueIndex, VeluxProduct.UNKNOWN);
     }
 
     public VeluxProduct get(ProductBridgeIndex bridgeProductIndex) {
         logger.trace("get({}) called.", bridgeProductIndex);
-        String serialNumber = bridgeIndexToSerialNumber.get(bridgeProductIndex.toInt());
-        if (!isRegistered(bridgeProductIndex) || serialNumber == null) {
-            return VeluxProduct.UNKNOWN;
-        }
-        return existingProductsByUniqueIndex.getOrDefault(serialNumber, VeluxProduct.UNKNOWN);
+        String unique = bridgeIndexToUniqueIndex.get(bridgeProductIndex.toInt());
+        return unique != null ? existingProductsByUniqueIndex.getOrDefault(unique, VeluxProduct.UNKNOWN)
+                : VeluxProduct.UNKNOWN;
     }
 
     public VeluxProduct[] values() {
index fc3d8f4c7e619d10b5f1bce21c420ca11d562770..82f80bef60eb3558b5957697d3d8f0246326e7f2 100644 (file)
@@ -217,7 +217,10 @@ public class VeluxProduct {
     // Class helper methods
 
     public String getProductUniqueIndex() {
-        return this.name.toString().concat("#").concat(this.typeId.toString());
+        if (!v2 || serialNumber.startsWith(VeluxProductSerialNo.UNKNOWN)) {
+            return name.toString();
+        }
+        return VeluxProductSerialNo.cleaned(serialNumber);
     }
 
     // Getter and Setter methods
index f0dfed6b1eadd79acff1ce9405e7dbf8879b460b..521810b1742725c6e7bb38eb4d2c0232cd82bcd9 100644 (file)
                        <label>@text/config.velux.thing.rollershutter.serial.label</label>
                        <description>@text/config.velux.thing.rollershutter.serial.description</description>
                        <required>true</required>
+                       <default>00:00:00:00:00:00:00:00</default>
                        <advanced>false</advanced>
                </parameter>
                <parameter name="name" type="text">