]> git.basschouten.com Git - openhab-addons.git/blob
dadeb7b2e5c334a31d0f91cf95596cc3bdb53a3b
[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.hue.internal.handler;
14
15 import org.eclipse.jdt.annotation.NonNullByDefault;
16 import org.eclipse.jdt.annotation.Nullable;
17 import org.openhab.binding.hue.internal.State;
18 import org.openhab.binding.hue.internal.State.AlertMode;
19 import org.openhab.binding.hue.internal.State.ColorMode;
20 import org.openhab.binding.hue.internal.State.Effect;
21 import org.openhab.binding.hue.internal.StateUpdate;
22 import org.openhab.core.library.types.DecimalType;
23 import org.openhab.core.library.types.HSBType;
24 import org.openhab.core.library.types.IncreaseDecreaseType;
25 import org.openhab.core.library.types.OnOffType;
26 import org.openhab.core.library.types.PercentType;
27 import org.openhab.core.library.types.StringType;
28
29 /**
30  * The {@link LightStateConverter} is responsible for mapping to/from jue types.
31  *
32  * @author Dennis Nobel - Initial contribution
33  * @author Oliver Libutzki - Adjustments
34  * @author Kai Kreuzer - made code static
35  * @author Andre Fuechsel - added method for brightness
36  * @author Yordan Zhelev - added method for alert
37  * @author Denis Dudnik - switched to internally integrated source of Jue library, minor code cleanup
38  * @author Christoph Weitkamp - Added support for bulbs using CIE XY colormode only
39  */
40 @NonNullByDefault
41 public class LightStateConverter {
42
43     private static final double HUE_FACTOR = 65535 / 360.0;
44     private static final double SATURATION_FACTOR = 2.54;
45     private static final double BRIGHTNESS_FACTOR = 2.54;
46
47     private static final int MIN_COLOR_TEMPERATURE = 153;
48     private static final int MAX_COLOR_TEMPERATURE = 500;
49     private static final int COLOR_TEMPERATURE_RANGE = MAX_COLOR_TEMPERATURE - MIN_COLOR_TEMPERATURE;
50
51     /**
52      * {@value #ALERT_MODE_NONE}. The light is not performing an alert effect.
53      */
54     static final String ALERT_MODE_NONE = "NONE";
55     /**
56      * {@value #ALERT_MODE_SELECT}. The light is performing one breathe cycle.
57      */
58     static final String ALERT_MODE_SELECT = "SELECT";
59     /**
60      * {@value #ALERT_MODE_LONG_SELECT}. The light is performing breathe cycles
61      * for 15 seconds or until an "alert": "none" command is received.
62      */
63     static final String ALERT_MODE_LONG_SELECT = "LSELECT";
64
65     private static final int DIM_STEPSIZE = 30;
66
67     /**
68      * Transforms the given {@link HSBType} into a light state.
69      *
70      * @param hsbType HSB type
71      * @return light state representing the {@link HSBType}.
72      */
73     public static StateUpdate toColorLightState(HSBType hsbType, State lightState) {
74         StateUpdate stateUpdate = ColorMode.XY.equals(lightState.getColorMode()) ? toXYColorLightState(hsbType)
75                 : toHSBColorLightState(hsbType);
76
77         int brightness = (int) Math.floor(hsbType.getBrightness().doubleValue() * BRIGHTNESS_FACTOR);
78         if (brightness > 0) {
79             stateUpdate.setBrightness(brightness);
80         }
81         return stateUpdate;
82     }
83
84     private static StateUpdate toHSBColorLightState(HSBType hsbType) {
85         int hue = (int) Math.round(hsbType.getHue().doubleValue() * HUE_FACTOR);
86         int saturation = (int) Math.floor(hsbType.getSaturation().doubleValue() * SATURATION_FACTOR);
87
88         return new StateUpdate().setHue(hue).setSat(saturation);
89     }
90
91     private static StateUpdate toXYColorLightState(HSBType hsbType) {
92         PercentType[] xy = hsbType.toXY();
93         float x = xy[0].floatValue() / 100.0f;
94         float y = xy[1].floatValue() / 100.0f;
95
96         return new StateUpdate().setXY(x, y);
97     }
98
99     /**
100      * Transforms the given {@link OnOffType} into a light state containing the
101      * 'on' value.
102      *
103      * @param onOffType on or off state
104      * @return light state containing the 'on' value
105      */
106     public static StateUpdate toOnOffLightState(OnOffType onOffType) {
107         return new StateUpdate().setOn(OnOffType.ON.equals(onOffType));
108     }
109
110     /**
111      * Transforms the given {@link PercentType} into a light state containing
112      * the brightness and the 'on' value represented by {@link PercentType}.
113      *
114      * @param percentType brightness represented as {@link PercentType}
115      * @return light state containing the brightness and the 'on' value
116      */
117     public static StateUpdate toBrightnessLightState(PercentType percentType) {
118         boolean on = !percentType.equals(PercentType.ZERO);
119         final StateUpdate stateUpdate = new StateUpdate().setOn(on);
120
121         int brightness = (int) Math.floor(percentType.doubleValue() * BRIGHTNESS_FACTOR);
122         if (brightness > 0) {
123             stateUpdate.setBrightness(brightness);
124         }
125         return stateUpdate;
126     }
127
128     /**
129      * Adjusts the given brightness using the {@link IncreaseDecreaseType} and
130      * returns the updated value.
131      *
132      * @param command The {@link IncreaseDecreaseType} to be used
133      * @param currentBrightness The current brightness
134      * @return The adjusted brightness value
135      */
136     public static int toAdjustedBrightness(IncreaseDecreaseType command, int currentBrightness) {
137         int newBrightness;
138         if (command == IncreaseDecreaseType.DECREASE) {
139             newBrightness = Math.max(currentBrightness - DIM_STEPSIZE, 0);
140         } else {
141             newBrightness = Math.min(currentBrightness + DIM_STEPSIZE, (int) (BRIGHTNESS_FACTOR * 100));
142         }
143         return newBrightness;
144     }
145
146     /**
147      * Transforms the given {@link PercentType} into a light state containing
148      * the color temperature represented by {@link PercentType}.
149      *
150      * @param percentType color temperature represented as {@link PercentType}
151      * @return light state containing the color temperature
152      */
153     public static StateUpdate toColorTemperatureLightState(PercentType percentType) {
154         int colorTemperature = MIN_COLOR_TEMPERATURE
155                 + Math.round((COLOR_TEMPERATURE_RANGE * percentType.floatValue()) / 100);
156         return new StateUpdate().setColorTemperature(colorTemperature);
157     }
158
159     /**
160      * Adjusts the given color temperature using the {@link IncreaseDecreaseType} and returns the updated value.
161      *
162      * @param type The {@link IncreaseDecreaseType} to be used
163      * @param currentColorTemp The current color temperature
164      * @return The adjusted color temperature value
165      */
166     public static int toAdjustedColorTemp(IncreaseDecreaseType type, int currentColorTemp) {
167         int newColorTemp;
168         if (type == IncreaseDecreaseType.DECREASE) {
169             newColorTemp = Math.max(currentColorTemp - DIM_STEPSIZE, MIN_COLOR_TEMPERATURE);
170         } else {
171             newColorTemp = Math.min(currentColorTemp + DIM_STEPSIZE, MAX_COLOR_TEMPERATURE);
172         }
173         return newColorTemp;
174     }
175
176     /**
177      * Transforms Hue Light {@link State} into {@link PercentType} representing
178      * the color temperature.
179      *
180      * @param lightState light state
181      * @return percent type representing the color temperature
182      */
183     public static PercentType toColorTemperaturePercentType(State lightState) {
184         int percent = (int) Math
185                 .round(((lightState.getColorTemperature() - MIN_COLOR_TEMPERATURE) * 100.0) / COLOR_TEMPERATURE_RANGE);
186         return new PercentType(restrictToBounds(percent));
187     }
188
189     /**
190      * Transforms Hue Light {@link State} into {@link PercentType} representing
191      * the brightness.
192      *
193      * @param lightState light state
194      * @return percent type representing the brightness
195      */
196     public static PercentType toBrightnessPercentType(State lightState) {
197         int percent = (int) Math.ceil(lightState.getBrightness() / BRIGHTNESS_FACTOR);
198         return new PercentType(restrictToBounds(percent));
199     }
200
201     /**
202      * Transforms {@link State} into {@link StringType} representing the {@link AlertMode}.
203      *
204      * @param lightState light state.
205      * @return string type representing the alert mode.
206      */
207     public static StringType toAlertStringType(State lightState) {
208         AlertMode alertMode = lightState.getAlertMode();
209         if (alertMode == null) {
210             return new StringType("NULL");
211         } else {
212             return new StringType(alertMode.toString());
213         }
214     }
215
216     /**
217      * Transforms Hue Light {@link State} into {@link HSBType} representing the
218      * color.
219      *
220      * @param lightState light state
221      * @return HSB type representing the color
222      */
223     public static HSBType toHSBType(State lightState) {
224         // even if color mode is reported to be XY, xy field of lightState might be null, while hsb is available
225         boolean isInXYMode = ColorMode.XY.equals(lightState.getColorMode()) && lightState.getXY() != null;
226         return isInXYMode ? fromXYtoHSBType(lightState) : fromHSBtoHSBType(lightState);
227     }
228
229     private static HSBType fromHSBtoHSBType(State lightState) {
230         int hue = (int) Math.round(lightState.getHue() / HUE_FACTOR) % 360;
231
232         int saturationInPercent = (int) Math.ceil(lightState.getSaturation() / SATURATION_FACTOR);
233         saturationInPercent = restrictToBounds(saturationInPercent);
234
235         int brightnessInPercent = (int) Math.ceil(lightState.getBrightness() / BRIGHTNESS_FACTOR);
236         brightnessInPercent = restrictToBounds(brightnessInPercent);
237
238         return new HSBType(new DecimalType(hue), new PercentType(saturationInPercent),
239                 new PercentType(brightnessInPercent));
240     }
241
242     private static HSBType fromXYtoHSBType(State lightState) {
243         float[] xy = lightState.getXY();
244         HSBType hsb = HSBType.fromXY(xy[0], xy[1]);
245
246         int brightnessInPercent = (int) Math.ceil(lightState.getBrightness() / BRIGHTNESS_FACTOR);
247         brightnessInPercent = restrictToBounds(brightnessInPercent);
248
249         return new HSBType(hsb.getHue(), hsb.getSaturation(), new PercentType(brightnessInPercent));
250     }
251
252     /**
253      * Transforms the given {@link StringType} into a light state containing the {@link AlertMode} to be triggered.
254      *
255      * @param alertType {@link StringType} representing the required {@link AlertMode} . <br>
256      *            Supported values are:
257      *            <ul>
258      *            <li>{@value #ALERT_MODE_NONE}.
259      *            <li>{@value #ALERT_MODE_SELECT}.
260      *            <li>{@value #ALERT_MODE_LONG_SELECT}.
261      *            <ul>
262      * @return light state containing the {@link AlertMode} or <b><code>null </code></b> if the provided
263      *         {@link StringType} represents unsupported mode.
264      */
265     public static @Nullable StateUpdate toAlertState(StringType alertType) {
266         AlertMode alertMode;
267
268         switch (alertType.toString()) {
269             case ALERT_MODE_NONE:
270                 alertMode = State.AlertMode.NONE;
271                 break;
272             case ALERT_MODE_SELECT:
273                 alertMode = State.AlertMode.SELECT;
274                 break;
275             case ALERT_MODE_LONG_SELECT:
276                 alertMode = State.AlertMode.LSELECT;
277                 break;
278             default:
279                 return null;
280         }
281         return new StateUpdate().setAlert(alertMode);
282     }
283
284     /**
285      * Transforms the given {@link OnOffType} into a light state containing the {@link Effect} value.
286      * {@link OnOffType#ON} will result in {@link Effect#COLORLOOP}. {@link OnOffType#OFF} will result in
287      * {@link Effect#NONE}.
288      *
289      * @param onOffType on or off state
290      * @return light state containing the {@link Effect} value
291      */
292     public static StateUpdate toOnOffEffectState(OnOffType onOffType) {
293         StateUpdate stateUpdate;
294
295         if (OnOffType.ON.equals(onOffType)) {
296             stateUpdate = new StateUpdate().setEffect(Effect.COLORLOOP);
297         } else {
298             stateUpdate = new StateUpdate().setEffect(Effect.NONE);
299         }
300
301         return stateUpdate;
302     }
303
304     private static int restrictToBounds(int percentValue) {
305         if (percentValue < 0) {
306             return 0;
307         } else if (percentValue > 100) {
308             return 100;
309         }
310         return percentValue;
311     }
312 }