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.hdpowerview.internal.api;
15 import static org.openhab.binding.hdpowerview.internal.api.CoordinateSystem.*;
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;
24 * The position of a single shade, as returned by the HD PowerView hub
26 * @author Andy Lintner - Initial contribution
27 * @author Andrew Fiddian-Green - Added support for secondary rail positions
30 public class ShadePosition {
32 * Primary actuator position
35 private int position1;
38 * Secondary actuator position
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
44 private @Nullable Integer posKind2 = null;
45 private @Nullable Integer position2 = null;
48 * Create a ShadePosition position instance with just a primary actuator
51 * @param coordSys the Coordinate System to be used
52 * @param percent the percentage position within that Coordinate System
53 * @return the ShadePosition instance
55 public static ShadePosition create(CoordinateSystem coordSys, int percent) {
56 return new ShadePosition(coordSys, percent, null, null);
60 * Create a ShadePosition position instance with both a primary and a secondary
63 * @param primaryCoordSys the Coordinate System to be used for the primary
65 * @param primaryPercent the percentage position for primary position
66 * @param secondaryCoordSys the Coordinate System to be used for the secondary
68 * @param secondaryPercent the percentage position for secondary position
69 * @return the ShadePosition instance
71 public static ShadePosition create(CoordinateSystem primaryCoordSys, int primaryPercent,
72 @Nullable CoordinateSystem secondaryCoordSys, @Nullable Integer secondaryPercent) {
73 return new ShadePosition(primaryCoordSys, primaryPercent, secondaryCoordSys, secondaryPercent);
77 * Constructor for ShadePosition position with both a primary and a secondary
80 * @param primaryCoordSys the Coordinate System to be used for the primary
82 * @param primaryPercent the percentage position for primary position
83 * @param secondaryCoordSys the Coordinate System to be used for the secondary
85 * @param secondaryPercent the percentage position for secondary position
87 ShadePosition(CoordinateSystem primaryCoordSys, int primaryPercent, @Nullable CoordinateSystem secondaryCoordSys,
88 @Nullable Integer secondaryPercent) {
89 setPosition1(primaryCoordSys, primaryPercent);
90 setPosition2(secondaryCoordSys, secondaryPercent);
94 * For a given Actuator Class and Coordinate System, map the ShadePosition's
95 * state to an OpenHAB State
97 * @param actuatorClass the requested Actuator Class
98 * @param coordSys the requested Coordinate System
99 * @return the corresponding OpenHAB State
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);
108 return UnDefType.UNDEF;
113 * Determine the Coordinate System used for the given Actuator Class (if any)
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
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());
129 return ERROR_UNKNOWN;
133 private void setPosition1(CoordinateSystem coordSys, int percent) {
134 posKind1 = coordSys.toPosKind();
138 * Primary rail of a single action bottom-up shade, or
139 * Primary, lower, bottom-up, rail of a dual action shade
143 * Primary rail of a single action top-down shade
145 * All these types use the same coordinate system; which is inverted in relation
148 position1 = MAX_SHADE - (int) Math.round(percent / 100d * MAX_SHADE);
152 * Vane angle of the primary rail of a bottom-up single action shade
154 position1 = (int) Math.round(percent / 100d * MAX_VANE);
161 private State getPosition1(CoordinateSystem coordSys) {
165 * Primary rail of a single action bottom-up shade, or
166 * Primary, lower, bottom-up, rail of a dual action shade
170 * Primary rail of a single action top-down shade
172 * All these types use the same coordinate system; which is inverted in relation
175 * If the slats have a defined position then the shade position must by
178 return posKind1 == 3 ? PercentType.HUNDRED
179 : new PercentType(100 - (int) Math.round((double) position1 / MAX_SHADE * 100));
183 * Vane angle of the primary rail of a bottom-up single action shade
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
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()
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));
197 return UnDefType.UNDEF;
201 private void setPosition2(@Nullable CoordinateSystem coordSys, @Nullable Integer percent) {
202 if (coordSys == null || percent == null) {
205 posKind2 = Integer.valueOf(coordSys.toPosKind());
210 * Secondary, upper, top-down rail of a dual action shade
212 * Uses a coordinate system that is NOT inverted in relation to OpenHAB
214 position2 = Integer.valueOf((int) Math.round(percent.doubleValue() / 100 * MAX_SHADE));
217 position2 = Integer.valueOf(0);
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;
230 * This case should never occur; but return a value anyway just in case
234 * Secondary, upper, top-down rail of a dual action shade
236 * Uses a coordinate system that is NOT inverted in relation to OpenHAB
238 if (posKind2.intValue() != 3) {
239 return new PercentType((int) Math.round(position2.doubleValue() / MAX_SHADE * 100));
242 return UnDefType.UNDEF;