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