2 * Copyright (c) 2010-2020 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.velux.internal.things;
15 import org.eclipse.jdt.annotation.NonNullByDefault;
16 import org.openhab.binding.velux.internal.VeluxBindingConstants;
17 import org.openhab.core.library.types.PercentType;
18 import org.slf4j.Logger;
19 import org.slf4j.LoggerFactory;
22 * <B>Velux</B> product characteristics: Product Position.
25 * "https://velcdn.azureedge.net/~/media/com/api/klf200/technical%20specification%20for%20klf%20200%20api.pdf#page=110">KLF200
26 * Standard Parameter definition</a>
28 * Methods in handle this type of information:
30 * <LI>{@link #VeluxProductPosition(int)} to convert a Velux value into the characteristic.</LI>
31 * <LI>{@link #VeluxProductPosition(PercentType)} to convert an openHAB value into the characteristic.</LI>
32 * <LI>{@link #VeluxProductPosition()} to convert an openHAB STOP value into the characteristic.</LI>
33 * <LI>{@link #isValid} to determine whether the characteristic has got a valid value.</LI>
34 * <LI>{@link #getPositionAsPercentType()} to convert the characteristic into an openHAB value.</LI>
35 * <LI>{@link #getPositionAsVeluxType()} to convert the characteristic into a Velux value.</LI>
36 * <LI>{@link #toString} to retrieve a human-readable description of this characteristic.</LI>
41 * @author Guenther Schreiner - initial contribution.
44 public class VeluxProductPosition {
45 private final Logger logger = LoggerFactory.getLogger(getClass());
49 public static final VeluxProductPosition UNKNOWN = new VeluxProductPosition();
50 public static final int VPP_VELUX_STOP = 0xD200;
51 public static final int VPP_VELUX_DEFAULT = 0xD300;
52 public static final int VPP_VELUX_IGNORE = 0xD400;
54 // Make sure that the calculation are done as non-integer
55 private static final float ONE = 1;
57 private static final int VPP_UNKNOWN = 0;
59 private static final int VPP_OPENHAB_MIN = 0;
60 private static final int VPP_OPENHAB_MAX = 100;
61 private static final int VPP_VELUX_MIN = 0x0000;
62 private static final int VPP_VELUX_MAX = 0xc800;
63 private static final int VPP_VELUX_UNKNOWN = 0xF7FF;
65 private static final int VPP_VELUX_PERCENTAGE_MIN = 0xc900;
66 private static final int VPP_VELUX_PERCENTAGE_MAX = 0xd0d0;
70 private PercentType position;
71 private boolean isValid = false;
76 * Creation of a Position object to specify a distinct actuator setting.
78 * @param position A position as type {@link PercentType} (between 0 and 100).
80 public VeluxProductPosition(PercentType position) {
81 logger.trace("VeluxProductPosition({} as PercentType) created.", position.intValue());
82 this.position = position;
87 * Creation of a Position object to specify a distinct actuator setting.
89 * @param position A position as type {@link PercentType} (between 0 and 100).
90 * @param toBeInverted Flag whether the value should be handled as inverted.
92 public VeluxProductPosition(PercentType position, boolean toBeInverted) {
93 this(toBeInverted ? new PercentType(PercentType.HUNDRED.intValue() - position.intValue()) : position);
97 * Creation of a Position object to specify a distinct actuator setting.
99 * @param veluxPosition A position as type {@link int} based on the Velux-specific value ranges (between 0x0000 and
100 * 0xc800, or 0xD200 for stop).
102 public VeluxProductPosition(int veluxPosition) {
103 logger.trace("VeluxProductPosition(constructur with {} as veluxPosition) called.", veluxPosition);
104 if ((veluxPosition == VPP_VELUX_UNKNOWN) || (veluxPosition == VPP_VELUX_STOP) || (veluxPosition < VPP_VELUX_MIN)
105 || (veluxPosition > VPP_VELUX_MAX)) {
106 logger.trace("VeluxProductPosition() gives up.");
107 this.position = new PercentType(VPP_UNKNOWN);
108 this.isValid = false;
110 float result = (ONE * veluxPosition - VPP_VELUX_MIN) / (VPP_VELUX_MAX - VPP_VELUX_MIN);
111 result = Math.round(VPP_OPENHAB_MIN + result * (VPP_OPENHAB_MAX - VPP_OPENHAB_MIN));
112 logger.trace("VeluxProductPosition() created with percent-type {}.", (int) result);
113 this.position = new PercentType((int) result);
119 * Creation of a Position object to specify a STOP.
121 public VeluxProductPosition() {
122 logger.trace("VeluxProductPosition() as STOP position created.");
123 this.position = new PercentType(VPP_UNKNOWN);
124 this.isValid = false;
127 // Class access methods
129 public boolean isValid() {
133 public PercentType getPositionAsPercentType() {
137 public PercentType getPositionAsPercentType(boolean toBeInverted) {
138 return toBeInverted ? new PercentType(PercentType.HUNDRED.intValue() - position.intValue()) : position;
141 public int getPositionAsVeluxType() {
143 float result = (ONE * position.intValue() - VPP_OPENHAB_MIN) / (VPP_OPENHAB_MAX - VPP_OPENHAB_MIN);
144 result = VPP_VELUX_MIN + result * (VPP_VELUX_MAX - VPP_VELUX_MIN);
147 return VPP_VELUX_STOP;
152 public String toString() {
154 return String.format("%d", position.intValue());
156 return new String(VeluxBindingConstants.UNKNOWN);
162 public static int getRelativePositionAsVeluxType(boolean upwards, PercentType position) {
163 float result = (VPP_VELUX_PERCENTAGE_MAX + VPP_VELUX_PERCENTAGE_MIN) / 2;
165 result = result + (ONE * position.intValue() - VPP_OPENHAB_MIN) / (VPP_OPENHAB_MAX - VPP_OPENHAB_MIN)
166 * ((VPP_VELUX_PERCENTAGE_MAX - VPP_VELUX_PERCENTAGE_MIN) / 2);
168 result = result - (ONE * position.intValue() - VPP_OPENHAB_MIN) / (VPP_OPENHAB_MAX - VPP_OPENHAB_MIN)
169 * ((VPP_VELUX_PERCENTAGE_MAX - VPP_VELUX_PERCENTAGE_MIN) / 2);