[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
@ -13,6 +13,7 @@
|
|||||||
package org.openhab.binding.velux.internal.bridge.common;
|
package org.openhab.binding.velux.internal.bridge.common;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.openhab.binding.velux.internal.things.StatusReply;
|
||||||
import org.openhab.binding.velux.internal.things.VeluxProduct;
|
import org.openhab.binding.velux.internal.things.VeluxProduct;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -47,4 +48,8 @@ public abstract class GetProduct implements BridgeCommunicationProtocol {
|
|||||||
* @return <b>veluxProduct</b> as VeluxProduct.
|
* @return <b>veluxProduct</b> as VeluxProduct.
|
||||||
*/
|
*/
|
||||||
public abstract VeluxProduct getProduct();
|
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.common.GetProduct;
|
||||||
import org.openhab.binding.velux.internal.bridge.slip.utils.KLF200Response;
|
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.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.Command;
|
||||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.CommandNumber;
|
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.CommandNumber;
|
||||||
import org.openhab.binding.velux.internal.things.VeluxProduct;
|
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 success = false;
|
||||||
private boolean finished = false;
|
private boolean finished = false;
|
||||||
|
|
||||||
private VeluxProduct product = VeluxProduct.UNKNOWN;
|
private VeluxProduct product = VeluxProduct.UNKNOWN;
|
||||||
|
private StatusReply statusReply = StatusReply.COMMAND_COMPLETED_OK;
|
||||||
|
|
||||||
public SCgetProductStatus() {
|
public SCgetProductStatus() {
|
||||||
logger.debug("SCgetProductStatus(Constructor) called.");
|
logger.debug("SCgetProductStatus(Constructor) called.");
|
||||||
@ -218,6 +219,7 @@ public class SCgetProductStatus extends GetProduct implements SlipBridgeCommunic
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ntfState = VeluxProduct.ProductState.ERROR.value;
|
ntfState = VeluxProduct.ProductState.ERROR.value;
|
||||||
|
statusReply = StatusReply.fromCode(ntfStatusReply);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -281,4 +283,9 @@ public class SCgetProductStatus extends GetProduct implements SlipBridgeCommunic
|
|||||||
logger.trace("getProduct(): returning {}.", product);
|
logger.trace("getProduct(): returning {}.", product);
|
||||||
return 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 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.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.binding.velux.internal.bridge.common.GetProduct;
|
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.FunctionalParameters;
|
||||||
import org.openhab.binding.velux.internal.bridge.slip.SCrunProductCommand;
|
import org.openhab.binding.velux.internal.bridge.slip.SCrunProductCommand;
|
||||||
import org.openhab.binding.velux.internal.handler.utils.Thing2VeluxActuator;
|
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.VeluxExistingProducts;
|
||||||
import org.openhab.binding.velux.internal.things.VeluxProduct;
|
import org.openhab.binding.velux.internal.things.VeluxProduct;
|
||||||
import org.openhab.binding.velux.internal.things.VeluxProduct.ProductBridgeIndex;
|
import org.openhab.binding.velux.internal.things.VeluxProduct.ProductBridgeIndex;
|
||||||
@ -71,12 +69,6 @@ final class ChannelActuatorPosition extends ChannelHandlerTemplate {
|
|||||||
throw new AssertionError();
|
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
|
// Public methods
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -105,12 +97,10 @@ final class ChannelActuatorPosition extends ChannelHandlerTemplate {
|
|||||||
|
|
||||||
GetProduct bcp = null;
|
GetProduct bcp = null;
|
||||||
switch (channelId) {
|
switch (channelId) {
|
||||||
case CHANNEL_VANE_POSITION:
|
|
||||||
bcp = thisBridgeHandler.thisBridge.bridgeAPI().getProductStatus();
|
|
||||||
break;
|
|
||||||
case CHANNEL_ACTUATOR_POSITION:
|
case CHANNEL_ACTUATOR_POSITION:
|
||||||
case CHANNEL_ACTUATOR_STATE:
|
case CHANNEL_ACTUATOR_STATE:
|
||||||
bcp = thisBridgeHandler.thisBridge.bridgeAPI().getProduct();
|
case CHANNEL_VANE_POSITION:
|
||||||
|
bcp = thisBridgeHandler.thisBridge.bridgeAPI().getProductStatus();
|
||||||
default:
|
default:
|
||||||
// unknown channel, will exit
|
// unknown channel, will exit
|
||||||
}
|
}
|
||||||
@ -127,45 +117,68 @@ final class ChannelActuatorPosition extends ChannelHandlerTemplate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
VeluxProduct newProduct = bcp.getProduct();
|
VeluxProduct newProduct = bcp.getProduct();
|
||||||
if (STATES_TO_PROCESS.contains(newProduct.getProductState())) {
|
ProductBridgeIndex productBridgeIndex = newProduct.getBridgeProductIndex();
|
||||||
ProductBridgeIndex productBridgeIndex = newProduct.getBridgeProductIndex();
|
VeluxExistingProducts existingProducts = thisBridgeHandler.existingProducts();
|
||||||
VeluxExistingProducts existingProducts = thisBridgeHandler.existingProducts();
|
VeluxProduct existingProduct = existingProducts.get(productBridgeIndex);
|
||||||
VeluxProduct existingProduct = existingProducts.get(productBridgeIndex);
|
ProductState productState = newProduct.getProductState();
|
||||||
if (!VeluxProduct.UNKNOWN.equals(existingProduct)) {
|
switch (productState) {
|
||||||
switch (channelId) {
|
case DONE:
|
||||||
case CHANNEL_VANE_POSITION:
|
case EXECUTING:
|
||||||
case CHANNEL_ACTUATOR_POSITION:
|
case MANUAL:
|
||||||
case CHANNEL_ACTUATOR_STATE: {
|
case UNKNOWN:
|
||||||
if (existingProducts.update(newProduct)) {
|
if (!VeluxProduct.UNKNOWN.equals(existingProduct)) {
|
||||||
existingProduct = existingProducts.get(productBridgeIndex);
|
switch (channelId) {
|
||||||
int posValue = VeluxProductPosition.VPP_VELUX_UNKNOWN;
|
case CHANNEL_VANE_POSITION:
|
||||||
switch (channelId) {
|
case CHANNEL_ACTUATOR_POSITION:
|
||||||
case CHANNEL_VANE_POSITION:
|
case CHANNEL_ACTUATOR_STATE: {
|
||||||
posValue = existingProduct.getVaneDisplayPosition();
|
if (existingProducts.update(newProduct)) {
|
||||||
break;
|
existingProduct = existingProducts.get(productBridgeIndex);
|
||||||
case CHANNEL_ACTUATOR_POSITION:
|
int posValue = VeluxProductPosition.VPP_VELUX_UNKNOWN;
|
||||||
case CHANNEL_ACTUATOR_STATE:
|
|
||||||
posValue = existingProduct.getDisplayPosition();
|
|
||||||
}
|
|
||||||
VeluxProductPosition position = new VeluxProductPosition(posValue);
|
|
||||||
if (position.isValid()) {
|
|
||||||
switch (channelId) {
|
switch (channelId) {
|
||||||
case CHANNEL_VANE_POSITION:
|
case CHANNEL_VANE_POSITION:
|
||||||
newState = position.getPositionAsPercentType(false);
|
posValue = existingProduct.getVaneDisplayPosition();
|
||||||
break;
|
break;
|
||||||
case CHANNEL_ACTUATOR_POSITION:
|
case CHANNEL_ACTUATOR_POSITION:
|
||||||
newState = position.getPositionAsPercentType(veluxActuator.isInverted());
|
|
||||||
break;
|
|
||||||
case CHANNEL_ACTUATOR_STATE:
|
case CHANNEL_ACTUATOR_STATE:
|
||||||
newState = OnOffType
|
posValue = existingProduct.getDisplayPosition();
|
||||||
.from(position.getPositionAsPercentType(veluxActuator.isInverted())
|
}
|
||||||
.intValue() > 50);
|
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) {
|
if (newState == null) {
|
||||||
|
|||||||
@ -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