2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.homematic.internal.converter.type;
15 import static org.openhab.binding.homematic.internal.misc.HomematicConstants.*;
17 import java.math.BigDecimal;
18 import java.math.RoundingMode;
19 import java.util.ArrayList;
20 import java.util.List;
22 import org.openhab.binding.homematic.internal.converter.ConverterException;
23 import org.openhab.binding.homematic.internal.converter.ConverterTypeException;
24 import org.openhab.binding.homematic.internal.converter.StateInvertInfo;
25 import org.openhab.binding.homematic.internal.converter.TypeConverter;
26 import org.openhab.binding.homematic.internal.model.HmDatapoint;
27 import org.openhab.binding.homematic.internal.model.HmDatapointInfo;
28 import org.openhab.core.types.Command;
29 import org.openhab.core.types.State;
30 import org.openhab.core.types.Type;
31 import org.openhab.core.types.UnDefType;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
36 * Base class for all Converters with common methods.
38 * @author Gerhard Riegler - Initial contribution
40 public abstract class AbstractTypeConverter<T extends State> implements TypeConverter<T> {
41 private final Logger logger = LoggerFactory.getLogger(AbstractTypeConverter.class);
44 * Defines all devices where the state datapoint must be inverted.
46 private static final List<StateInvertInfo> STATE_INVERT_INFO_LIST = new ArrayList<>(3);
49 STATE_INVERT_INFO_LIST.add(new StateInvertInfo(DEVICE_TYPE_SHUTTER_CONTACT));
50 STATE_INVERT_INFO_LIST.add(new StateInvertInfo(DEVICE_TYPE_SHUTTER_CONTACT_2));
51 STATE_INVERT_INFO_LIST.add(new StateInvertInfo(DEVICE_TYPE_INCLINATION_SENSOR));
52 STATE_INVERT_INFO_LIST.add(new StateInvertInfo(DEVICE_TYPE_WIRED_IO_MODULE, 15, 26));
53 STATE_INVERT_INFO_LIST.add(new StateInvertInfo(DEVICE_TYPE_MAX_WINDOW_SENSOR));
54 STATE_INVERT_INFO_LIST.add(new StateInvertInfo(DEVICE_TYPE_SHUTTER_CONTACT_INTERFACE));
58 * Checks the datapoint if the state value must be inverted.
60 protected boolean isStateInvertDatapoint(HmDatapoint dp) {
61 if (DATAPOINT_NAME_STATE.equals(dp.getName())) {
62 for (StateInvertInfo stateInvertInfo : STATE_INVERT_INFO_LIST) {
63 if (stateInvertInfo.isToInvert(dp)) {
72 * Rounds a double value.
74 protected BigDecimal round(Double number) {
75 BigDecimal bd = new BigDecimal(number == null ? "0" : number.toString());
76 String stringBd = bd.toPlainString();
77 int scale = stringBd.length() - (stringBd.lastIndexOf('.') + 1);
78 return bd.setScale(scale > 2 ? 6 : 2, RoundingMode.HALF_UP);
81 @SuppressWarnings("unchecked")
83 public Object convertToBinding(Type type, HmDatapoint dp) throws ConverterException {
84 if (isLoggingRequired()) {
86 "Converting type {} with value '{}' using {} to datapoint '{}' (dpType='{}', dpUnit='{}')",
87 type.getClass().getSimpleName(), type.toString(), this.getClass().getSimpleName(),
88 new HmDatapointInfo(dp), dp.getType(), dp.getUnit());
91 if (type == UnDefType.NULL) {
93 } else if (type.getClass().isEnum() && !(this instanceof OnOffTypeConverter)
94 && !(this instanceof OpenClosedTypeConverter)) {
95 return commandToBinding((Command) type, dp);
96 } else if (!toBindingValidation(dp, type.getClass())) {
97 String errorMessage = String.format("Can't convert type %s with value '%s' to %s value with %s for '%s'",
98 type.getClass().getSimpleName(), type.toString(), dp.getType(), this.getClass().getSimpleName(),
99 new HmDatapointInfo(dp));
100 throw new ConverterTypeException(errorMessage);
103 return toBinding((T) type, dp);
106 @SuppressWarnings("unchecked")
108 public T convertFromBinding(HmDatapoint dp) throws ConverterException {
109 if (isLoggingRequired()) {
110 logAtDefaultLevel("Converting datapoint '{}' (dpType='{}', dpUnit='{}', dpValue='{}') with {}",
111 new HmDatapointInfo(dp), dp.getType(), dp.getUnit(), dp.getValue(),
112 this.getClass().getSimpleName());
115 if (dp.getValue() == null) {
116 return (T) UnDefType.NULL;
117 } else if (!fromBindingValidation(dp)) {
118 logger.debug("Can't convert {} value '{}' with {} for '{}'", dp.getType(), dp.getValue(),
119 this.getClass().getSimpleName(), new HmDatapointInfo(dp));
120 return (T) UnDefType.NULL;
123 return fromBinding(dp);
127 * By default, instances of {@link AbstractTypeConverter} log in level TRACE.
128 * May be overridden to increase logging verbosity of a converter.
130 * @return desired LogLevel
132 protected LogLevel getDefaultLogLevelForTypeConverter() {
133 return LogLevel.TRACE;
136 private boolean isLoggingRequired() {
137 if (getDefaultLogLevelForTypeConverter() == LogLevel.TRACE) {
138 return logger.isTraceEnabled();
140 if (getDefaultLogLevelForTypeConverter() == LogLevel.DEBUG) {
141 return logger.isDebugEnabled();
146 private void logAtDefaultLevel(String format, Object... arguments) {
147 switch (getDefaultLogLevelForTypeConverter()) {
149 logger.trace(format, arguments);
152 logger.debug(format, arguments);
156 logger.info(format, arguments);
162 * Converts an openHAB command to a Homematic value.
164 protected Object commandToBinding(Command command, HmDatapoint dp) throws ConverterException {
165 throw new ConverterException("Unsupported command " + command.getClass().getSimpleName() + " for "
166 + this.getClass().getSimpleName());
170 * Returns true, if the conversion from openHAB to the binding is possible.
172 protected abstract boolean toBindingValidation(HmDatapoint dp, Class<? extends Type> typeClass);
175 * Converts the type to a datapoint value.
177 protected abstract Object toBinding(T type, HmDatapoint dp) throws ConverterException;
180 * Returns true, if the conversion from the binding to openHAB is possible.
182 protected abstract boolean fromBindingValidation(HmDatapoint dp);
185 * Converts the datapoint value to an openHAB type.
187 protected abstract T fromBinding(HmDatapoint dp) throws ConverterException;
189 protected enum LogLevel {