2 * Copyright (c) 2010-2021 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;
62 public static final int VPP_VELUX_MIN = 0x0000;
63 public static final int VPP_VELUX_MAX = 0xc800;
64 public static final int VPP_VELUX_UNKNOWN = 0xF7FF;
66 // relative mode commands
67 private static final int VPP_VELUX_RELATIVE_ORIGIN = 0xCCE8;
68 private static final int VPP_VELUX_RELATIVE_RANGE = 1000; // same for positive and negative offsets
72 private PercentType position;
73 private boolean isValid = false;
78 * Creation of a Position object to specify a distinct actuator setting.
80 * @param position A position as type {@link PercentType} (between 0 and 100).
82 public VeluxProductPosition(PercentType position) {
83 logger.trace("VeluxProductPosition({} as PercentType) created.", position.intValue());
84 this.position = position;
89 * Creation of a Position object to specify a distinct actuator setting.
91 * @param position A position as type {@link PercentType} (between 0 and 100).
92 * @param toBeInverted Flag whether the value should be handled as inverted.
94 public VeluxProductPosition(PercentType position, boolean toBeInverted) {
95 this(toBeInverted ? new PercentType(PercentType.HUNDRED.intValue() - position.intValue()) : position);
99 * Creation of a Position object to specify a distinct actuator setting.
101 * @param veluxPosition A position as type {@link int} based on the Velux-specific value ranges (between 0x0000 and
102 * 0xc800, or 0xD200 for stop).
104 public VeluxProductPosition(int veluxPosition) {
105 logger.trace("VeluxProductPosition(constructur with {} as veluxPosition) called.", veluxPosition);
106 if ((veluxPosition == VPP_VELUX_UNKNOWN) || (veluxPosition == VPP_VELUX_STOP) || (veluxPosition < VPP_VELUX_MIN)
107 || (veluxPosition > VPP_VELUX_MAX)) {
108 logger.trace("VeluxProductPosition() gives up.");
109 this.position = new PercentType(VPP_UNKNOWN);
110 this.isValid = false;
112 float result = (ONE * veluxPosition - VPP_VELUX_MIN) / (VPP_VELUX_MAX - VPP_VELUX_MIN);
113 result = Math.round(VPP_OPENHAB_MIN + result * (VPP_OPENHAB_MAX - VPP_OPENHAB_MIN));
114 logger.trace("VeluxProductPosition() created with percent-type {}.", (int) result);
115 this.position = new PercentType((int) result);
121 * Creation of a Position object to specify a STOP.
123 public VeluxProductPosition() {
124 logger.trace("VeluxProductPosition() as STOP position created.");
125 this.position = new PercentType(VPP_UNKNOWN);
126 this.isValid = false;
129 // Class access methods
131 public boolean isValid() {
135 public PercentType getPositionAsPercentType() {
139 public PercentType getPositionAsPercentType(boolean toBeInverted) {
140 return toBeInverted ? new PercentType(PercentType.HUNDRED.intValue() - position.intValue()) : position;
143 public int getPositionAsVeluxType() {
145 float result = (ONE * position.intValue() - VPP_OPENHAB_MIN) / (VPP_OPENHAB_MAX - VPP_OPENHAB_MIN);
146 result = VPP_VELUX_MIN + result * (VPP_VELUX_MAX - VPP_VELUX_MIN);
149 return VPP_VELUX_STOP;
154 public String toString() {
156 return String.format("%d", position.intValue());
158 return new String(VeluxBindingConstants.UNKNOWN);
164 public int getAsRelativePosition(boolean positive) {
165 int offset = position.intValue() * VPP_VELUX_RELATIVE_RANGE / (VPP_OPENHAB_MAX - VPP_OPENHAB_MIN);
166 return positive ? VPP_VELUX_RELATIVE_ORIGIN + offset : VPP_VELUX_RELATIVE_ORIGIN - offset;