diff --git a/bundles/org.openhab.binding.velux/README.md b/bundles/org.openhab.binding.velux/README.md index fc08919fc..ec0ced276 100644 --- a/bundles/org.openhab.binding.velux/README.md +++ b/bundles/org.openhab.binding.velux/README.md @@ -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 | ,,,,.... | -| 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 diff --git a/bundles/org.openhab.binding.velux/src/main/java/org/openhab/binding/velux/internal/VeluxBindingConstants.java b/bundles/org.openhab.binding.velux/src/main/java/org/openhab/binding/velux/internal/VeluxBindingConstants.java index 739be2184..3f7012b99 100644 --- a/bundles/org.openhab.binding.velux/src/main/java/org/openhab/binding/velux/internal/VeluxBindingConstants.java +++ b/bundles/org.openhab.binding.velux/src/main/java/org/openhab/binding/velux/internal/VeluxBindingConstants.java @@ -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(); } diff --git a/bundles/org.openhab.binding.velux/src/main/java/org/openhab/binding/velux/internal/handler/ChannelActuatorPosition.java b/bundles/org.openhab.binding.velux/src/main/java/org/openhab/binding/velux/internal/handler/ChannelActuatorPosition.java index c9b83f063..f9af1bc0c 100644 --- a/bundles/org.openhab.binding.velux/src/main/java/org/openhab/binding/velux/internal/handler/ChannelActuatorPosition.java +++ b/bundles/org.openhab.binding.velux/src/main/java/org/openhab/binding/velux/internal/handler/ChannelActuatorPosition.java @@ -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."); } diff --git a/bundles/org.openhab.binding.velux/src/main/java/org/openhab/binding/velux/internal/handler/VeluxBridgeHandler.java b/bundles/org.openhab.binding.velux/src/main/java/org/openhab/binding/velux/internal/handler/VeluxBridgeHandler.java index 0fe7f2efa..04f4898f6 100644 --- a/bundles/org.openhab.binding.velux/src/main/java/org/openhab/binding/velux/internal/handler/VeluxBridgeHandler.java +++ b/bundles/org.openhab.binding.velux/src/main/java/org/openhab/binding/velux/internal/handler/VeluxBridgeHandler.java @@ -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; } diff --git a/bundles/org.openhab.binding.velux/src/main/java/org/openhab/binding/velux/internal/handler/utils/Thing2VeluxActuator.java b/bundles/org.openhab.binding.velux/src/main/java/org/openhab/binding/velux/internal/handler/utils/Thing2VeluxActuator.java index f86cbbf0d..916c21c62 100644 --- a/bundles/org.openhab.binding.velux/src/main/java/org/openhab/binding/velux/internal/handler/utils/Thing2VeluxActuator.java +++ b/bundles/org.openhab.binding.velux/src/main/java/org/openhab/binding/velux/internal/handler/utils/Thing2VeluxActuator.java @@ -13,8 +13,10 @@ 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; } - isInverted = propertyInverted || VeluxProductSerialNo.indicatesRevertedValues(actuatorSerial); - logger.trace("mapThing2Velux(): found isInverted={}.", isInverted); - actuatorSerial = VeluxProductSerialNo.cleaned(actuatorSerial); + logger.trace("mapThing2Velux(): in {} serialNumber={}.", channelUID, uniqueIndex); - if (!bridgeHandler.bridgeParameters.actuators.getChannel().existingProducts.isRegistered(actuatorSerial)) { - logger.warn("mapThing2Velux(): cannot work on unknown actuator with serial {}.", actuatorSerial); + // 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 = invert; + logger.trace("mapThing2Velux(): in {} isInverted={}.", channelUID, isInverted); + + 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; } diff --git a/bundles/org.openhab.binding.velux/src/main/java/org/openhab/binding/velux/internal/things/VeluxExistingProducts.java b/bundles/org.openhab.binding.velux/src/main/java/org/openhab/binding/velux/internal/things/VeluxExistingProducts.java index 51c18f312..592c379a9 100644 --- a/bundles/org.openhab.binding.velux/src/main/java/org/openhab/binding/velux/internal/things/VeluxExistingProducts.java +++ b/bundles/org.openhab.binding.velux/src/main/java/org/openhab/binding/velux/internal/things/VeluxExistingProducts.java @@ -47,7 +47,7 @@ public class VeluxExistingProducts { // Type definitions, class-internal variables private Map existingProductsByUniqueIndex; - private Map bridgeIndexToSerialNumber; + private Map bridgeIndexToUniqueIndex; private Map 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() { diff --git a/bundles/org.openhab.binding.velux/src/main/java/org/openhab/binding/velux/internal/things/VeluxProduct.java b/bundles/org.openhab.binding.velux/src/main/java/org/openhab/binding/velux/internal/things/VeluxProduct.java index fc3d8f4c7..82f80bef6 100644 --- a/bundles/org.openhab.binding.velux/src/main/java/org/openhab/binding/velux/internal/things/VeluxProduct.java +++ b/bundles/org.openhab.binding.velux/src/main/java/org/openhab/binding/velux/internal/things/VeluxProduct.java @@ -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 diff --git a/bundles/org.openhab.binding.velux/src/main/resources/OH-INF/config/config.xml b/bundles/org.openhab.binding.velux/src/main/resources/OH-INF/config/config.xml index f0dfed6b1..521810b17 100644 --- a/bundles/org.openhab.binding.velux/src/main/resources/OH-INF/config/config.xml +++ b/bundles/org.openhab.binding.velux/src/main/resources/OH-INF/config/config.xml @@ -138,6 +138,7 @@ @text/config.velux.thing.rollershutter.serial.description true + 00:00:00:00:00:00:00:00 false