[velux] fix bugs with Somfy devices, and switch devices (#9245)
* [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>
This commit is contained in:
committed by
GitHub
parent
d2e5c3e7dd
commit
ce5d5ca61d
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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.");
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -138,6 +138,7 @@
|
||||
<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">
|
||||
|
||||
Reference in New Issue
Block a user