]> git.basschouten.com Git - openhab-addons.git/blob
77dbaa9cbee65135483afe931f2e41bade9ccb17
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.velux.internal.things;
14
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;
20
21 /**
22  * <B>Velux</B> product characteristics: Product Position.
23  * <P>
24  * See <a href=
25  * "https://velcdn.azureedge.net/~/media/com/api/klf200/technical%20specification%20for%20klf%20200%20api.pdf#page=110">KLF200
26  * Standard Parameter definition</a>
27  * <P>
28  * Methods in handle this type of information:
29  * <UL>
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>
37  * </UL>
38  *
39  * @see VeluxKLFAPI
40  *
41  * @author Guenther Schreiner - initial contribution.
42  */
43 @NonNullByDefault
44 public class VeluxProductPosition {
45     private final Logger logger = LoggerFactory.getLogger(getClass());
46
47     // Public definition
48
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;
53
54     // Make sure that the calculation are done as non-integer
55     private static final float ONE = 1;
56
57     private static final int VPP_UNKNOWN = 0;
58
59     private static final int VPP_OPENHAB_MIN = 0;
60     private static final int VPP_OPENHAB_MAX = 100;
61
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;
65
66     // relative mode commands
67     public static final int VPP_VELUX_RELATIVE_ORIGIN = 0xCCE8;
68     public static final int VPP_VELUX_RELATIVE_RANGE = 1000; // same for positive and negative offsets
69
70     /**
71      * Enum that determines whether the position is an absolute value, or a positive / negative offset relative to the
72      * current position.
73      *
74      * @author AndrewFG - Initial contribution.
75      */
76     public enum PositionType {
77         ABSOLUTE_VALUE(0f),
78         OFFSET_POSITIVE(1f),
79         OFFSET_NEGATIVE(-1f);
80
81         private float value;
82
83         private PositionType(float i) {
84             value = i;
85         }
86     }
87
88     // Class internal
89
90     private PercentType position;
91     private boolean isValid = false;
92     private PositionType positionType = PositionType.ABSOLUTE_VALUE;
93
94     // Constructor
95
96     /**
97      * Creation of a Position object to specify a distinct actuator setting.
98      *
99      * @param position A position as type {@link PercentType} (between 0 and 100).
100      */
101     public VeluxProductPosition(PercentType position) {
102         logger.trace("VeluxProductPosition({} as PercentType) created.", position.intValue());
103         this.position = position;
104         this.isValid = true;
105     }
106
107     /**
108      * Creation of a Position object to specify a distinct actuator setting.
109      *
110      * @param position A position as type {@link PercentType} (between 0 and 100).
111      * @param toBeInverted Flag whether the value should be handled as inverted.
112      */
113     public VeluxProductPosition(PercentType position, boolean toBeInverted) {
114         this(toBeInverted ? new PercentType(PercentType.HUNDRED.intValue() - position.intValue()) : position);
115     }
116
117     /**
118      * Creation of a Position object to specify a distinct actuator setting.
119      *
120      * @param veluxPosition A position as type {@link int} based on the Velux-specific value ranges (between 0x0000 and
121      *            0xc800, or 0xD200 for stop).
122      */
123     public VeluxProductPosition(int veluxPosition) {
124         logger.trace("VeluxProductPosition(constructor with {} as veluxPosition) called.", veluxPosition);
125         if (isValid(veluxPosition)) {
126             float result = (ONE * veluxPosition - VPP_VELUX_MIN) / (VPP_VELUX_MAX - VPP_VELUX_MIN);
127             result = Math.round(VPP_OPENHAB_MIN + result * (VPP_OPENHAB_MAX - VPP_OPENHAB_MIN));
128             this.position = new PercentType((int) result);
129             this.isValid = true;
130             logger.trace("VeluxProductPosition() created with percent-type {}.", (int) result);
131         } else {
132             this.position = new PercentType(VPP_UNKNOWN);
133             this.isValid = false;
134             logger.trace("VeluxProductPosition() gives up.");
135         }
136     }
137
138     public static boolean isValid(int position) {
139         return (position <= VeluxProductPosition.VPP_VELUX_MAX) && (position >= VeluxProductPosition.VPP_VELUX_MIN);
140     }
141
142     public static boolean isUnknownOrValid(int position) {
143         return (position == VeluxProductPosition.VPP_VELUX_UNKNOWN) || isValid(position);
144     }
145
146     /**
147      * Creation of a Position object to specify a STOP.
148      */
149     public VeluxProductPosition() {
150         logger.trace("VeluxProductPosition() as STOP position created.");
151         this.position = new PercentType(VPP_UNKNOWN);
152         this.isValid = false;
153     }
154
155     // Class access methods
156
157     public boolean isValid() {
158         return this.isValid;
159     }
160
161     public PercentType getPositionAsPercentType() {
162         return position;
163     }
164
165     public PercentType getPositionAsPercentType(boolean toBeInverted) {
166         return toBeInverted ? new PercentType(PercentType.HUNDRED.intValue() - position.intValue()) : position;
167     }
168
169     public int getPositionAsVeluxType() {
170         if (this.isValid) {
171             float result;
172             if (positionType == PositionType.ABSOLUTE_VALUE) {
173                 result = (ONE * position.intValue() - VPP_OPENHAB_MIN) / (VPP_OPENHAB_MAX - VPP_OPENHAB_MIN);
174                 result = VPP_VELUX_MIN + result * (VPP_VELUX_MAX - VPP_VELUX_MIN);
175             } else {
176                 result = VPP_VELUX_RELATIVE_ORIGIN
177                         + ((positionType.value * position.intValue() * VPP_VELUX_RELATIVE_RANGE)
178                                 / (VPP_OPENHAB_MAX - VPP_OPENHAB_MIN));
179             }
180             return (int) result;
181         } else {
182             return VPP_VELUX_STOP;
183         }
184     }
185
186     @Override
187     public String toString() {
188         if (this.isValid) {
189             return String.format("%d", position.intValue());
190         } else {
191             return new String(VeluxBindingConstants.UNKNOWN);
192         }
193     }
194
195     // Helper methods
196
197     public VeluxProductPosition overridePositionType(PositionType positionType) {
198         this.positionType = positionType;
199         return this;
200     }
201 }