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