]> git.basschouten.com Git - openhab-addons.git/blob
df400725a316598125969b3533e332427e8a1aa5
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 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.dto.clip2.helper;
14
15 import java.math.BigDecimal;
16 import java.time.Duration;
17 import java.util.List;
18 import java.util.Objects;
19
20 import javax.measure.Unit;
21
22 import org.eclipse.jdt.annotation.NonNullByDefault;
23 import org.eclipse.jdt.annotation.Nullable;
24 import org.openhab.binding.hue.internal.dto.clip2.Alerts;
25 import org.openhab.binding.hue.internal.dto.clip2.ColorTemperature;
26 import org.openhab.binding.hue.internal.dto.clip2.ColorXy;
27 import org.openhab.binding.hue.internal.dto.clip2.Dimming;
28 import org.openhab.binding.hue.internal.dto.clip2.Effects;
29 import org.openhab.binding.hue.internal.dto.clip2.MetaData;
30 import org.openhab.binding.hue.internal.dto.clip2.MirekSchema;
31 import org.openhab.binding.hue.internal.dto.clip2.OnState;
32 import org.openhab.binding.hue.internal.dto.clip2.Resource;
33 import org.openhab.binding.hue.internal.dto.clip2.TimedEffects;
34 import org.openhab.binding.hue.internal.dto.clip2.enums.ActionType;
35 import org.openhab.binding.hue.internal.dto.clip2.enums.EffectType;
36 import org.openhab.core.library.types.DecimalType;
37 import org.openhab.core.library.types.HSBType;
38 import org.openhab.core.library.types.PercentType;
39 import org.openhab.core.library.types.QuantityType;
40 import org.openhab.core.library.types.StringType;
41 import org.openhab.core.library.unit.Units;
42 import org.openhab.core.types.Command;
43 import org.openhab.core.util.ColorUtil;
44 import org.openhab.core.util.ColorUtil.Gamut;
45
46 /**
47  * Advanced setter methods for fields in the Resource class for special cases where setting the new value in the target
48  * resource depends on logic using the values of other fields in a another source Resource.
49  *
50  * @author Andrew Fiddian-Green - Initial contribution
51  */
52 @NonNullByDefault
53 public class Setters {
54
55     /**
56      * Setter for Alert field:
57      * Use the given command value to set the target resource DTO value based on the attributes of the source resource
58      * (if any).
59      *
60      * @param target the target resource.
61      * @param command the new state command should be a StringType.
62      * @param source another resource containing the allowed alert action values.
63      *
64      * @return the target resource.
65      */
66     public static Resource setAlert(Resource target, Command command, @Nullable Resource source) {
67         if ((command instanceof StringType) && Objects.nonNull(source)) {
68             Alerts otherAlert = source.getAlerts();
69             if (Objects.nonNull(otherAlert)) {
70                 ActionType actionType = ActionType.of(((StringType) command).toString());
71                 if (otherAlert.getActionValues().contains(actionType)) {
72                     target.setAlerts(new Alerts().setAction(actionType));
73                 }
74             }
75         }
76         return target;
77     }
78
79     /**
80      * Setter for Color Temperature field:
81      * Use the given command value to set the target resource DTO value based on the attributes of the source resource
82      * (if any).
83      *
84      * @param target the target resource.
85      * @param command the new state command should be a {@code QuantityType<Temperature>} (but it can also handle
86      *            {@code DecimalType}).
87      * @param source another resource containing the MirekSchema.
88      *
89      * @return the target resource.
90      */
91     public static Resource setColorTemperatureAbsolute(Resource target, Command command, @Nullable Resource source) {
92         QuantityType<?> mirek;
93         if (command instanceof QuantityType<?>) {
94             QuantityType<?> quantity = (QuantityType<?>) command;
95             Unit<?> unit = quantity.getUnit();
96             if (Units.KELVIN.equals(unit)) {
97                 mirek = quantity.toInvertibleUnit(Units.MIRED);
98             } else if (Units.MIRED.equals(unit)) {
99                 mirek = quantity;
100             } else {
101                 QuantityType<?> kelvin = quantity.toInvertibleUnit(Units.KELVIN);
102                 mirek = Objects.nonNull(kelvin) ? kelvin.toInvertibleUnit(Units.MIRED) : null;
103             }
104         } else if (command instanceof DecimalType) {
105             mirek = QuantityType.valueOf(((DecimalType) command).doubleValue(), Units.KELVIN)
106                     .toInvertibleUnit(Units.MIRED);
107         } else {
108             mirek = null;
109         }
110         if (Objects.nonNull(mirek)) {
111             MirekSchema schema = target.getMirekSchema();
112             schema = Objects.nonNull(schema) ? schema : Objects.nonNull(source) ? source.getMirekSchema() : null;
113             schema = Objects.nonNull(schema) ? schema : MirekSchema.DEFAULT_SCHEMA;
114             ColorTemperature colorTemperature = target.getColorTemperature();
115             colorTemperature = Objects.nonNull(colorTemperature) ? colorTemperature : new ColorTemperature();
116             double min = schema.getMirekMinimum();
117             double max = schema.getMirekMaximum();
118             double val = Math.max(min, Math.min(max, mirek.doubleValue()));
119             target.setColorTemperature(colorTemperature.setMirek(val));
120         }
121         return target;
122     }
123
124     /**
125      * Setter for Color Temperature field:
126      * Use the given command value to set the target resource DTO value based on the attributes of the source resource
127      * (if any).
128      *
129      * @param target the target resource.
130      * @param command the new state command should be a PercentType.
131      * @param source another resource containing the MirekSchema.
132      *
133      * @return the target resource.
134      */
135     public static Resource setColorTemperaturePercent(Resource target, Command command, @Nullable Resource source) {
136         if (command instanceof PercentType) {
137             MirekSchema schema = target.getMirekSchema();
138             schema = Objects.nonNull(schema) ? schema : Objects.nonNull(source) ? source.getMirekSchema() : null;
139             schema = Objects.nonNull(schema) ? schema : MirekSchema.DEFAULT_SCHEMA;
140             ColorTemperature colorTemperature = target.getColorTemperature();
141             colorTemperature = Objects.nonNull(colorTemperature) ? colorTemperature : new ColorTemperature();
142             double min = schema.getMirekMinimum();
143             double max = schema.getMirekMaximum();
144             double val = min + ((max - min) * ((PercentType) command).doubleValue() / 100f);
145             target.setColorTemperature(colorTemperature.setMirek(val));
146         }
147         return target;
148     }
149
150     /**
151      * Setter for Color Xy field:
152      * Use the given command value to set the target resource DTO value based on the attributes of the source resource
153      * (if any). Use the HS parts of the HSB value to set the value of the 'ColorXy' JSON element, and ignore the 'B'
154      * part.
155      *
156      * @param target the target resource.
157      * @param command the new state command should be an HSBType with the new color XY value.
158      * @param source another resource containing the color Gamut.
159      *
160      * @return the target resource.
161      */
162     public static Resource setColorXy(Resource target, Command command, @Nullable Resource source) {
163         if (command instanceof HSBType) {
164             Gamut gamut = target.getGamut();
165             gamut = Objects.nonNull(gamut) ? gamut : Objects.nonNull(source) ? source.getGamut() : null;
166             gamut = Objects.nonNull(gamut) ? gamut : ColorUtil.DEFAULT_GAMUT;
167             HSBType hsb = (HSBType) command;
168             ColorXy color = target.getColorXy();
169             target.setColorXy((Objects.nonNull(color) ? color : new ColorXy()).setXY(ColorUtil.hsbToXY(hsb, gamut)));
170         }
171         return target;
172     }
173
174     /**
175      * Setter for Dimming field:
176      * Use the given command value to set the target resource DTO value based on the attributes of the source resource
177      * (if any).
178      *
179      * @param target the target resource.
180      * @param command the new state command should be a PercentType with the new dimming parameter.
181      * @param source another resource containing the minimum dimming level.
182      *
183      * @return the target resource.
184      */
185     public static Resource setDimming(Resource target, Command command, @Nullable Resource source) {
186         if (command instanceof PercentType) {
187             Double min = target.getMinimumDimmingLevel();
188             min = Objects.nonNull(min) ? min : Objects.nonNull(source) ? source.getMinimumDimmingLevel() : null;
189             min = Objects.nonNull(min) ? min : Dimming.DEFAULT_MINIMUM_DIMMIMG_LEVEL;
190             PercentType brightness = (PercentType) command;
191             if (brightness.doubleValue() < min.doubleValue()) {
192                 brightness = new PercentType(new BigDecimal(min, Resource.PERCENT_MATH_CONTEXT));
193             }
194             Dimming dimming = target.getDimming();
195             dimming = Objects.nonNull(dimming) ? dimming : new Dimming();
196             dimming.setBrightness(brightness.doubleValue());
197             target.setDimming(dimming);
198         }
199         return target;
200     }
201
202     /**
203      * Setter for fixed or timed effect field:
204      * Use the given command value to set the target fixed or timed effects resource DTO value based on the attributes
205      * of the source resource (if any).
206      *
207      * @param target the target resource.
208      * @param command the new state command should be a StringType.
209      * @param source another resource containing the allowed effect action values.
210      *
211      * @return the target resource.
212      */
213     public static Resource setEffect(Resource target, Command command, @Nullable Resource source) {
214         if ((command instanceof StringType) && Objects.nonNull(source)) {
215             EffectType commandEffectType = EffectType.of(((StringType) command).toString());
216             Effects sourceFixedEffects = source.getFixedEffects();
217             if (Objects.nonNull(sourceFixedEffects) && sourceFixedEffects.allows(commandEffectType)) {
218                 target.setFixedEffects(new Effects().setEffect(commandEffectType));
219             }
220             TimedEffects sourceTimedEffects = source.getTimedEffects();
221             if (Objects.nonNull(sourceTimedEffects) && sourceTimedEffects.allows(commandEffectType)) {
222                 Duration duration = sourceTimedEffects.getDuration();
223                 target.setTimedEffects(((TimedEffects) new TimedEffects().setEffect(commandEffectType))
224                         .setDuration(Objects.nonNull(duration) ? duration : TimedEffects.DEFAULT_DURATION));
225             }
226         }
227         return target;
228     }
229
230     /**
231      * Setter to copy persisted fields from the source Resource into the target Resource. If the field in the target is
232      * null and the same field in the source is not null, then the value from the source is copied to the target. This
233      * method allows 'hasSparseData' resources to expand themselves to include necessary fields taken over from a
234      * previously cached full data resource.
235      *
236      * @param target the target resource.
237      * @param source another resource containing the values to be taken over.
238      *
239      * @return the target resource.
240      */
241     public static Resource setResource(Resource target, Resource source) {
242         // on
243         OnState targetOnOff = target.getOnState();
244         OnState sourceOnOff = source.getOnState();
245         if (Objects.isNull(targetOnOff) && Objects.nonNull(sourceOnOff)) {
246             target.setOnState(sourceOnOff);
247         }
248
249         // dimming
250         Dimming targetDimming = target.getDimming();
251         Dimming sourceDimming = source.getDimming();
252         if (Objects.isNull(targetDimming) && Objects.nonNull(sourceDimming)) {
253             target.setDimming(sourceDimming);
254             targetDimming = target.getDimming();
255         }
256
257         // minimum dimming level
258         if (Objects.nonNull(targetDimming)) {
259             Double sourceMinDimLevel = Objects.isNull(sourceDimming) ? null : sourceDimming.getMinimumDimmingLevel();
260             if (Objects.nonNull(sourceMinDimLevel)) {
261                 targetDimming.setMinimumDimmingLevel(sourceMinDimLevel);
262             }
263         }
264
265         // color
266         ColorXy targetColor = target.getColorXy();
267         ColorXy sourceColor = source.getColorXy();
268         if (Objects.isNull(targetColor) && Objects.nonNull(sourceColor)) {
269             target.setColorXy(sourceColor);
270             targetColor = target.getColorXy();
271         }
272
273         // color gamut
274         Gamut sourceGamut = Objects.isNull(sourceColor) ? null : sourceColor.getGamut();
275         if (Objects.nonNull(targetColor) && Objects.nonNull(sourceGamut)) {
276             targetColor.setGamut(sourceGamut);
277         }
278
279         // color temperature
280         ColorTemperature targetColorTemp = target.getColorTemperature();
281         ColorTemperature sourceColorTemp = source.getColorTemperature();
282         if (Objects.isNull(targetColorTemp) && Objects.nonNull(sourceColorTemp)) {
283             target.setColorTemperature(sourceColorTemp);
284             targetColorTemp = target.getColorTemperature();
285         }
286
287         // mirek schema
288         if (Objects.nonNull(targetColorTemp)) {
289             MirekSchema sourceMirekSchema = Objects.isNull(sourceColorTemp) ? null : sourceColorTemp.getMirekSchema();
290             if (Objects.nonNull(sourceMirekSchema)) {
291                 targetColorTemp.setMirekSchema(sourceMirekSchema);
292             }
293         }
294
295         // metadata
296         MetaData targetMetaData = target.getMetaData();
297         MetaData sourceMetaData = source.getMetaData();
298         if (Objects.isNull(targetMetaData) && Objects.nonNull(sourceMetaData)) {
299             target.setMetadata(sourceMetaData);
300         }
301
302         // alerts
303         Alerts targetAlerts = target.getAlerts();
304         Alerts sourceAlerts = source.getAlerts();
305         if (Objects.isNull(targetAlerts) && Objects.nonNull(sourceAlerts)) {
306             target.setAlerts(sourceAlerts);
307         }
308
309         // fixed effects
310         Effects targetFixedEffects = target.getFixedEffects();
311         Effects sourceFixedEffects = source.getFixedEffects();
312         if (Objects.isNull(targetFixedEffects) && Objects.nonNull(sourceFixedEffects)) {
313             target.setFixedEffects(sourceFixedEffects);
314             targetFixedEffects = target.getFixedEffects();
315         }
316
317         // fixed effects allowed values
318         if (Objects.nonNull(targetFixedEffects)) {
319             List<String> values = Objects.isNull(sourceFixedEffects) ? List.of() : sourceFixedEffects.getStatusValues();
320             if (!values.isEmpty()) {
321                 targetFixedEffects.setStatusValues(values);
322             }
323         }
324
325         // timed effects
326         TimedEffects targetTimedEffects = target.getTimedEffects();
327         TimedEffects sourceTimedEffects = source.getTimedEffects();
328         if (Objects.isNull(targetTimedEffects) && Objects.nonNull(sourceTimedEffects)) {
329             target.setTimedEffects(sourceTimedEffects);
330             targetTimedEffects = target.getTimedEffects();
331         }
332
333         // timed effects allowed values and duration
334         if (Objects.nonNull(targetTimedEffects)) {
335             List<String> values = Objects.isNull(sourceTimedEffects) ? List.of() : sourceTimedEffects.getStatusValues();
336             if (!values.isEmpty()) {
337                 targetTimedEffects.setStatusValues(values);
338             }
339             Duration duration = Objects.isNull(sourceTimedEffects) ? null : sourceTimedEffects.getDuration();
340             if (Objects.nonNull(duration)) {
341                 targetTimedEffects.setDuration(duration);
342             }
343         }
344
345         return target;
346     }
347 }