[velux] Implement new API, and log critical device errors (#13212)
* [velux] use new API, and log StatusReply codes Signed-off-by: Andrew Fiddian-Green <software@whitebear.ch> Signed-off-by: Andrew Fiddian-Green <software@whitebear.ch>
This commit is contained in:
parent
d5e3ab797c
commit
b075d3781c
bundles/org.openhab.binding.velux/src/main/java/org/openhab/binding/velux/internal
bridge
handler
things
@ -13,6 +13,7 @@
|
||||
package org.openhab.binding.velux.internal.bridge.common;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.things.StatusReply;
|
||||
import org.openhab.binding.velux.internal.things.VeluxProduct;
|
||||
|
||||
/**
|
||||
@ -47,4 +48,8 @@ public abstract class GetProduct implements BridgeCommunicationProtocol {
|
||||
* @return <b>veluxProduct</b> as VeluxProduct.
|
||||
*/
|
||||
public abstract VeluxProduct getProduct();
|
||||
|
||||
public StatusReply getStatusReply() {
|
||||
return StatusReply.COMMAND_COMPLETED_OK;
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetProduct;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.KLF200Response;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.Packet;
|
||||
import org.openhab.binding.velux.internal.things.StatusReply;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.Command;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.CommandNumber;
|
||||
import org.openhab.binding.velux.internal.things.VeluxProduct;
|
||||
@ -81,8 +82,8 @@ public class SCgetProductStatus extends GetProduct implements SlipBridgeCommunic
|
||||
|
||||
private boolean success = false;
|
||||
private boolean finished = false;
|
||||
|
||||
private VeluxProduct product = VeluxProduct.UNKNOWN;
|
||||
private StatusReply statusReply = StatusReply.COMMAND_COMPLETED_OK;
|
||||
|
||||
public SCgetProductStatus() {
|
||||
logger.debug("SCgetProductStatus(Constructor) called.");
|
||||
@ -218,6 +219,7 @@ public class SCgetProductStatus extends GetProduct implements SlipBridgeCommunic
|
||||
break;
|
||||
default:
|
||||
ntfState = VeluxProduct.ProductState.ERROR.value;
|
||||
statusReply = StatusReply.fromCode(ntfStatusReply);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -281,4 +283,9 @@ public class SCgetProductStatus extends GetProduct implements SlipBridgeCommunic
|
||||
logger.trace("getProduct(): returning {}.", product);
|
||||
return product;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatusReply getStatusReply() {
|
||||
return statusReply;
|
||||
}
|
||||
}
|
||||
|
@ -14,9 +14,6 @@ package org.openhab.binding.velux.internal.handler;
|
||||
|
||||
import static org.openhab.binding.velux.internal.VeluxBindingConstants.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetProduct;
|
||||
@ -24,6 +21,7 @@ import org.openhab.binding.velux.internal.bridge.common.RunProductCommand;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.FunctionalParameters;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.SCrunProductCommand;
|
||||
import org.openhab.binding.velux.internal.handler.utils.Thing2VeluxActuator;
|
||||
import org.openhab.binding.velux.internal.things.StatusReply;
|
||||
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;
|
||||
@ -71,12 +69,6 @@ final class ChannelActuatorPosition extends ChannelHandlerTemplate {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
/*
|
||||
* List of product states that shall be processed
|
||||
*/
|
||||
private static final List<ProductState> STATES_TO_PROCESS = Arrays.asList(ProductState.DONE, ProductState.EXECUTING,
|
||||
ProductState.MANUAL, ProductState.UNKNOWN);
|
||||
|
||||
// Public methods
|
||||
|
||||
/**
|
||||
@ -105,12 +97,10 @@ final class ChannelActuatorPosition extends ChannelHandlerTemplate {
|
||||
|
||||
GetProduct bcp = null;
|
||||
switch (channelId) {
|
||||
case CHANNEL_VANE_POSITION:
|
||||
bcp = thisBridgeHandler.thisBridge.bridgeAPI().getProductStatus();
|
||||
break;
|
||||
case CHANNEL_ACTUATOR_POSITION:
|
||||
case CHANNEL_ACTUATOR_STATE:
|
||||
bcp = thisBridgeHandler.thisBridge.bridgeAPI().getProduct();
|
||||
case CHANNEL_VANE_POSITION:
|
||||
bcp = thisBridgeHandler.thisBridge.bridgeAPI().getProductStatus();
|
||||
default:
|
||||
// unknown channel, will exit
|
||||
}
|
||||
@ -127,45 +117,68 @@ final class ChannelActuatorPosition extends ChannelHandlerTemplate {
|
||||
}
|
||||
|
||||
VeluxProduct newProduct = bcp.getProduct();
|
||||
if (STATES_TO_PROCESS.contains(newProduct.getProductState())) {
|
||||
ProductBridgeIndex productBridgeIndex = newProduct.getBridgeProductIndex();
|
||||
VeluxExistingProducts existingProducts = thisBridgeHandler.existingProducts();
|
||||
VeluxProduct existingProduct = existingProducts.get(productBridgeIndex);
|
||||
if (!VeluxProduct.UNKNOWN.equals(existingProduct)) {
|
||||
switch (channelId) {
|
||||
case CHANNEL_VANE_POSITION:
|
||||
case CHANNEL_ACTUATOR_POSITION:
|
||||
case CHANNEL_ACTUATOR_STATE: {
|
||||
if (existingProducts.update(newProduct)) {
|
||||
existingProduct = existingProducts.get(productBridgeIndex);
|
||||
int posValue = VeluxProductPosition.VPP_VELUX_UNKNOWN;
|
||||
switch (channelId) {
|
||||
case CHANNEL_VANE_POSITION:
|
||||
posValue = existingProduct.getVaneDisplayPosition();
|
||||
break;
|
||||
case CHANNEL_ACTUATOR_POSITION:
|
||||
case CHANNEL_ACTUATOR_STATE:
|
||||
posValue = existingProduct.getDisplayPosition();
|
||||
}
|
||||
VeluxProductPosition position = new VeluxProductPosition(posValue);
|
||||
if (position.isValid()) {
|
||||
ProductBridgeIndex productBridgeIndex = newProduct.getBridgeProductIndex();
|
||||
VeluxExistingProducts existingProducts = thisBridgeHandler.existingProducts();
|
||||
VeluxProduct existingProduct = existingProducts.get(productBridgeIndex);
|
||||
ProductState productState = newProduct.getProductState();
|
||||
switch (productState) {
|
||||
case DONE:
|
||||
case EXECUTING:
|
||||
case MANUAL:
|
||||
case UNKNOWN:
|
||||
if (!VeluxProduct.UNKNOWN.equals(existingProduct)) {
|
||||
switch (channelId) {
|
||||
case CHANNEL_VANE_POSITION:
|
||||
case CHANNEL_ACTUATOR_POSITION:
|
||||
case CHANNEL_ACTUATOR_STATE: {
|
||||
if (existingProducts.update(newProduct)) {
|
||||
existingProduct = existingProducts.get(productBridgeIndex);
|
||||
int posValue = VeluxProductPosition.VPP_VELUX_UNKNOWN;
|
||||
switch (channelId) {
|
||||
case CHANNEL_VANE_POSITION:
|
||||
newState = position.getPositionAsPercentType(false);
|
||||
posValue = existingProduct.getVaneDisplayPosition();
|
||||
break;
|
||||
case CHANNEL_ACTUATOR_POSITION:
|
||||
newState = position.getPositionAsPercentType(veluxActuator.isInverted());
|
||||
break;
|
||||
case CHANNEL_ACTUATOR_STATE:
|
||||
newState = OnOffType
|
||||
.from(position.getPositionAsPercentType(veluxActuator.isInverted())
|
||||
.intValue() > 50);
|
||||
posValue = existingProduct.getDisplayPosition();
|
||||
}
|
||||
VeluxProductPosition position = new VeluxProductPosition(posValue);
|
||||
if (position.isValid()) {
|
||||
switch (channelId) {
|
||||
case CHANNEL_VANE_POSITION:
|
||||
newState = position.getPositionAsPercentType(false);
|
||||
break;
|
||||
case CHANNEL_ACTUATOR_POSITION:
|
||||
newState = position
|
||||
.getPositionAsPercentType(veluxActuator.isInverted());
|
||||
break;
|
||||
case CHANNEL_ACTUATOR_STATE:
|
||||
newState = OnOffType.from(
|
||||
position.getPositionAsPercentType(veluxActuator.isInverted())
|
||||
.intValue() > 50);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WAITING_FOR_POWER:
|
||||
case ERROR:
|
||||
StatusReply statusReply = productState == ProductState.WAITING_FOR_POWER
|
||||
? StatusReply.NODE_WAITING_FOR_POWER
|
||||
: bcp.getStatusReply();
|
||||
if (statusReply.isError()) {
|
||||
String id = VeluxProduct.UNKNOWN.equals(existingProduct)
|
||||
? newProduct.getBridgeProductIndex().toString()
|
||||
: existingProduct.getProductUniqueIndex();
|
||||
if (statusReply.isCriticalError()) {
|
||||
LOGGER.warn("Product Id:{} encountered an error with StatusReply:{}", id, statusReply);
|
||||
} else {
|
||||
LOGGER.info("Product Id:{} encountered an error with StatusReply:{}", id, statusReply);
|
||||
}
|
||||
}
|
||||
default:
|
||||
}
|
||||
|
||||
if (newState == null) {
|
||||
|
123
bundles/org.openhab.binding.velux/src/main/java/org/openhab/binding/velux/internal/things/StatusReply.java
Normal file
123
bundles/org.openhab.binding.velux/src/main/java/org/openhab/binding/velux/internal/things/StatusReply.java
Normal file
@ -0,0 +1,123 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.velux.internal.things;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* An enum that describes the various predefined Status Reply code values and their meanings.
|
||||
*
|
||||
* @author Andrew Fiddian-Green - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum StatusReply {
|
||||
UNKNOWN_STATUS_REPLY(0x00),
|
||||
COMMAND_COMPLETED_OK(0x01),
|
||||
NO_CONTACT(0x02),
|
||||
MANUALLY_OPERATED(0x03),
|
||||
BLOCKED(0x04),
|
||||
WRONG_SYSTEMKEY(0x05),
|
||||
PRIORITY_LEVEL_LOCKED(0x06),
|
||||
REACHED_WRONG_POSITION(0x07),
|
||||
ERROR_DURING_EXECUTION(0x08),
|
||||
NO_EXECUTION(0x09),
|
||||
CALIBRATING(0x0A),
|
||||
POWER_CONSUMPTION_TOO_HIGH(0x0B),
|
||||
POWER_CONSUMPTION_TOO_LOW(0x0C),
|
||||
LOCK_POSITION_OPEN(0x0D),
|
||||
MOTION_TIME_TOO_LONG(0x0E),
|
||||
THERMAL_PROTECTION(0x0F),
|
||||
PRODUCT_NOT_OPERATIONAL(0x10),
|
||||
FILTER_MAINTENANCE_NEEDED(0x11),
|
||||
BATTERY_LEVEL(0x12),
|
||||
TARGET_MODIFIED(0x13),
|
||||
MODE_NOT_IMPLEMENTED(0x14),
|
||||
COMMAND_INCOMPATIBLE_TO_MOVEMENT(0x15),
|
||||
USER_ACTION(0x16),
|
||||
DEAD_BOLT_ERROR(0x17),
|
||||
AUTOMATIC_CYCLE_ENGAGED(0x18),
|
||||
WRONG_LOAD_CONNECTED(0x19),
|
||||
COLOUR_NOT_REACHABLE(0x1A),
|
||||
TARGET_NOT_REACHABLE(0x1B),
|
||||
BAD_INDEX_RECEIVED(0x1C),
|
||||
COMMAND_OVERRULED(0x1D),
|
||||
NODE_WAITING_FOR_POWER(0x1E),
|
||||
INFORMATION_CODE(0xDF),
|
||||
PARAMETER_LIMITED(0xE0),
|
||||
LIMITATION_BY_LOCAL_USER(0xE1),
|
||||
LIMITATION_BY_USER(0xE2),
|
||||
LIMITATION_BY_RAIN(0xE3),
|
||||
LIMITATION_BY_TIMER(0xE4),
|
||||
LIMITATION_BY_UPS(0xE6),
|
||||
LIMITATION_BY_UNKNOWN_DEVICE(0xE7),
|
||||
LIMITATION_BY_SAAC(0xEA),
|
||||
LIMITATION_BY_WIND(0xEB),
|
||||
LIMITATION_BY_MYSELF(0xEC),
|
||||
LIMITATION_BY_AUTOMATIC_CYCLE(0xED),
|
||||
LIMITATION_BY_EMERGENCY(0xEE);
|
||||
|
||||
private final int code;
|
||||
|
||||
private StatusReply(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
/*
|
||||
* List of critical errors
|
||||
*/
|
||||
private static final List<StatusReply> CRITICAL_ERRORS = List.of(BLOCKED, POWER_CONSUMPTION_TOO_HIGH,
|
||||
THERMAL_PROTECTION, LOCK_POSITION_OPEN, PRODUCT_NOT_OPERATIONAL, DEAD_BOLT_ERROR, FILTER_MAINTENANCE_NEEDED,
|
||||
BATTERY_LEVEL, NODE_WAITING_FOR_POWER);
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
private static final Map<Integer, StatusReply> LOOKUP = Stream.of(StatusReply.values())
|
||||
.collect(Collectors.toMap(StatusReply::getCode, Function.identity()));
|
||||
|
||||
/**
|
||||
* Get the StatusReply value that corresponds to the given status code.
|
||||
*
|
||||
* @param statusReplyCode the status code value
|
||||
* @return the StatusReply value that corresponds to the status code
|
||||
*/
|
||||
public static StatusReply fromCode(int statusReplyCode) {
|
||||
return LOOKUP.getOrDefault(statusReplyCode, UNKNOWN_STATUS_REPLY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this Status Reply indicates an error.
|
||||
*
|
||||
* @return true if the status code is an error code.
|
||||
*/
|
||||
public boolean isError() {
|
||||
return this != COMMAND_COMPLETED_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this Status Reply indicates a critical error.
|
||||
*
|
||||
* @return true if the status code is a critical error code.
|
||||
*/
|
||||
public boolean isCriticalError() {
|
||||
return isError() && CRITICAL_ERRORS.contains(this);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user