]> git.basschouten.com Git - openhab-addons.git/blob
c449c49fb85584657e092cf9b1caf901c3655238
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2020 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.hdpowerview.internal.api;
14
15 import static org.openhab.binding.hdpowerview.internal.api.CoordinateSystem.*;
16
17 import org.eclipse.jdt.annotation.NonNullByDefault;
18 import org.eclipse.jdt.annotation.Nullable;
19 import org.openhab.core.library.types.PercentType;
20 import org.openhab.core.types.*;
21
22 /**
23  * The position of a single shade, as returned by the HD PowerView hub
24  *
25  * @author Andy Lintner - Initial contribution
26  * @author Andrew Fiddian-Green - Added support for secondary rail positions
27  */
28 @NonNullByDefault
29 public class ShadePosition {
30     /**
31      * Primary actuator position
32      */
33     private int posKind1;
34     private int position1;
35
36     /**
37      * Secondary actuator position
38      * 
39      * here we have to use Integer objects rather than just int primitives because
40      * these are secondary optional position elements in the JSON payload, so the
41      * GSON de-serializer might leave them as null
42      */
43     private @Nullable Integer posKind2 = null;
44     private @Nullable Integer position2 = null;
45
46     /**
47      * Create a ShadePosition position instance with just a primary actuator
48      * position
49      * 
50      * @param coordSys the Coordinate System to be used
51      * @param percent the percentage position within that Coordinate System
52      * @return the ShadePosition instance
53      */
54     public static ShadePosition create(CoordinateSystem coordSys, int percent) {
55         return new ShadePosition(coordSys, percent, null, null);
56     }
57
58     /**
59      * Create a ShadePosition position instance with both a primary and a secondary
60      * actuator position
61      * 
62      * @param primaryCoordSys the Coordinate System to be used for the primary
63      *            position
64      * @param primaryPercent the percentage position for primary position
65      * @param secondaryCoordSys the Coordinate System to be used for the secondary
66      *            position
67      * @param secondaryPercent the percentage position for secondary position
68      * @return the ShadePosition instance
69      */
70     public static ShadePosition create(CoordinateSystem primaryCoordSys, int primaryPercent,
71             @Nullable CoordinateSystem secondaryCoordSys, @Nullable Integer secondaryPercent) {
72         return new ShadePosition(primaryCoordSys, primaryPercent, secondaryCoordSys, secondaryPercent);
73     }
74
75     /**
76      * Constructor for ShadePosition position with both a primary and a secondary
77      * actuator position
78      * 
79      * @param primaryCoordSys the Coordinate System to be used for the primary
80      *            position
81      * @param primaryPercent the percentage position for primary position
82      * @param secondaryCoordSys the Coordinate System to be used for the secondary
83      *            position
84      * @param secondaryPercent the percentage position for secondary position
85      */
86     ShadePosition(CoordinateSystem primaryCoordSys, int primaryPercent, @Nullable CoordinateSystem secondaryCoordSys,
87             @Nullable Integer secondaryPercent) {
88         setPosition1(primaryCoordSys, primaryPercent);
89         setPosition2(secondaryCoordSys, secondaryPercent);
90     }
91
92     /**
93      * For a given Actuator Class and Coordinate System, map the ShadePosition's
94      * state to an OpenHAB State
95      * 
96      * @param actuatorClass the requested Actuator Class
97      * @param coordSys the requested Coordinate System
98      * @return the corresponding OpenHAB State
99      */
100     public State getState(ActuatorClass actuatorClass, CoordinateSystem coordSys) {
101         switch (actuatorClass) {
102             case PRIMARY_ACTUATOR:
103                 return getPosition1(coordSys);
104             case SECONDARY_ACTUATOR:
105                 return getPosition2(coordSys);
106             default:
107                 return UnDefType.UNDEF;
108         }
109     }
110
111     /**
112      * Determine the Coordinate System used for the given Actuator Class (if any)
113      * 
114      * @param actuatorClass the requested Actuator Class
115      * @return the Coordinate System used for that Actuator Class, or ERROR_UNKNOWN
116      *         if the Actuator Class is not implemented
117      */
118     public CoordinateSystem getCoordinateSystem(ActuatorClass actuatorClass) {
119         switch (actuatorClass) {
120             case PRIMARY_ACTUATOR:
121                 return fromPosKind(posKind1);
122             case SECONDARY_ACTUATOR:
123                 Integer posKind2 = this.posKind2;
124                 if (posKind2 != null) {
125                     return fromPosKind(posKind2.intValue());
126                 }
127             default:
128                 return ERROR_UNKNOWN;
129         }
130     }
131
132     private void setPosition1(CoordinateSystem coordSys, int percent) {
133         posKind1 = coordSys.toPosKind();
134         switch (coordSys) {
135             case ZERO_IS_CLOSED:
136                 /*-
137                  * Primary rail of a single action bottom-up shade, or
138                  * Primary, lower, bottom-up, rail of a dual action shade
139                  */
140             case ZERO_IS_OPEN:
141                 /*-
142                  * Primary rail of a single action top-down shade
143                  *
144                  * All these types use the same coordinate system; which is inverted in relation
145                  * to that of OpenHAB
146                  */
147                 position1 = MAX_SHADE - (int) Math.round(percent / 100d * MAX_SHADE);
148                 break;
149             case VANE_COORDS:
150                 /*
151                  * Vane angle of the primary rail of a bottom-up single action shade
152                  */
153                 position1 = (int) Math.round(percent / 100d * MAX_VANE);
154                 break;
155             default:
156                 position1 = 0;
157         }
158     }
159
160     private State getPosition1(CoordinateSystem coordSys) {
161         switch (coordSys) {
162             case ZERO_IS_CLOSED:
163                 /*-
164                  * Primary rail of a single action bottom-up shade, or
165                  * Primary, lower, bottom-up, rail of a dual action shade
166                  */
167             case ZERO_IS_OPEN:
168                 /*
169                  * Primary rail of a single action top-down shade
170                  *
171                  * All these types use the same coordinate system; which is inverted in relation
172                  * to that of OpenHAB
173                  * 
174                  * If the slats have a defined position then the shade position must by
175                  * definition be 100%
176                  */
177                 return posKind1 == 3 ? PercentType.HUNDRED
178                         : new PercentType(100 - (int) Math.round((double) position1 / MAX_SHADE * 100));
179
180             case VANE_COORDS:
181                 /*
182                  * Vane angle of the primary rail of a bottom-up single action shade
183                  * 
184                  * If the shades are not open, the vane position is undefined; if the the shades
185                  * are exactly open then the vanes are at zero; otherwise return the actual vane
186                  * position itself
187                  * 
188                  * note: sometimes the hub may return a value of position1 > MAX_VANE (seems to
189                  * be a bug in the hub) so we avoid an out of range exception via the Math.min()
190                  * function below..
191                  */
192                 return posKind1 != 3 ? (position1 != 0 ? UnDefType.UNDEF : PercentType.ZERO)
193                         : new PercentType((int) Math.round((double) Math.min(position1, MAX_VANE) / MAX_VANE * 100));
194
195             default:
196                 return UnDefType.UNDEF;
197         }
198     }
199
200     private void setPosition2(@Nullable CoordinateSystem coordSys, @Nullable Integer percent) {
201         if (coordSys == null || percent == null) {
202             return;
203         }
204         posKind2 = Integer.valueOf(coordSys.toPosKind());
205         switch (coordSys) {
206             case ZERO_IS_CLOSED:
207             case ZERO_IS_OPEN:
208                 /*
209                  * Secondary, upper, top-down rail of a dual action shade
210                  * 
211                  * Uses a coordinate system that is NOT inverted in relation to OpenHAB
212                  */
213                 position2 = Integer.valueOf((int) Math.round(percent.doubleValue() / 100 * MAX_SHADE));
214                 break;
215             default:
216                 position2 = Integer.valueOf(0);
217         }
218     }
219
220     private State getPosition2(CoordinateSystem coordSys) {
221         Integer posKind2 = this.posKind2;
222         Integer position2 = this.position2;
223         if (position2 == null || posKind2 == null) {
224             return UnDefType.UNDEF;
225         }
226         switch (coordSys) {
227             case ZERO_IS_CLOSED:
228                 /*
229                  * This case should never occur; but return a value anyway just in case
230                  */
231             case ZERO_IS_OPEN:
232                 /*
233                  * Secondary, upper, top-down rail of a dual action shade
234                  * 
235                  * Uses a coordinate system that is NOT inverted in relation to OpenHAB
236                  */
237                 if (posKind2.intValue() != 3) {
238                     return new PercentType(100 - (int) Math.round(position2.doubleValue() / MAX_SHADE * 100));
239                 }
240             default:
241                 return UnDefType.UNDEF;
242         }
243     }
244 }