3232/**
3333 * The {@link LightStateMachine} provides a state machine with helper functions for controlloing lights.
3434 * See also {@link ColorUtil} for more general color conversion utilities.
35+ *
36+ * <pre>
37+ * {@code
38+ * Set<String> s;
39+ * System.out.println(s);
40+ * }
41+ * </pre>
3542 *
3643 * @author Andrew Fiddian-Green - Initial contribution
3744 */
@@ -78,26 +85,26 @@ public LightStateMachine() {
7885 * Create a LightStateMachine with the given capabilities.
7986 *
8087 * @param supportsBrightness true if the light supports brightness control
81- * @param supportsColor true if the light supports color control
8288 * @param supportsColorTemperature true if the light supports color temperature control
89+ * @param supportsColor true if the light supports color control
8390 */
84- public LightStateMachine (boolean supportsBrightness , boolean supportsColor , boolean supportsColorTemperature ) {
85- this (supportsBrightness , supportsColor , supportsColorTemperature , null , null , null , null );
91+ public LightStateMachine (boolean supportsBrightness , boolean supportsColorTemperature , boolean supportsColor ) {
92+ this (supportsBrightness , supportsColorTemperature , supportsColor , null , null , null , null );
8693 }
8794
8895 /**
8996 * Create a LightStateMachine with the given capabilities and parameters.
9097 * The parameters can be null to use the default.
9198 *
9299 * @param supportsBrightness true if the light supports brightness control
93- * @param supportsColor true if the light supports color control
94100 * @param supportsColorTemperature true if the light supports color temperature control
101+ * @param supportsColor true if the light supports color control
95102 * @param minimumOnBrightness the minimum brightness percent to consider as light "ON"
96103 * @param warmestMired the 'warmest' white color temperature in Mired
97104 * @param coolestMired the 'coolest' white color temperature in Mired
98105 * @param stepSize the step size for IncreaseDecreaseType commands
99106 */
100- public LightStateMachine (boolean supportsBrightness , boolean supportsColor , boolean supportsColorTemperature ,
107+ public LightStateMachine (boolean supportsBrightness , boolean supportsColorTemperature , boolean supportsColor ,
101108 @ Nullable Double minimumOnBrightness , @ Nullable Double warmestMired , @ Nullable Double coolestMired ,
102109 @ Nullable Double stepSize ) {
103110 this .supportsColor = supportsColor ;
@@ -107,6 +114,7 @@ public LightStateMachine(boolean supportsBrightness, boolean supportsColor, bool
107114 this .warmestMired = warmestMired != null ? warmestMired : this .warmestMired ;
108115 this .coolestMired = coolestMired != null ? coolestMired : this .coolestMired ;
109116 this .stepSize = stepSize != null ? stepSize : this .stepSize ;
117+ validateParameters ();
110118 }
111119
112120 /**
@@ -163,9 +171,10 @@ public void handleColorTemperatureCommand(Command command) {
163171 setColorTemperature (warmness );
164172 } else if (command instanceof QuantityType <?> temperature ) {
165173 setColorTemperature (temperature );
174+ } else {
175+ throw new IllegalArgumentException (
176+ "Command '%s' not supported for color temperatures" .formatted (command .getClass ().getName ()));
166177 }
167- throw new IllegalArgumentException (
168- "Command '%s' not supported for color temperatures" .formatted (command .getClass ().getName ()));
169178 }
170179
171180 /**
@@ -188,9 +197,10 @@ public void handleCommand(Command command) {
188197 setBrightness (incDec );
189198 } else if (command instanceof QuantityType <?> temperature ) {
190199 setColorTemperature (temperature );
200+ } else {
201+ throw new IllegalArgumentException (
202+ "Command '%s' not supported for light states" .formatted (command .getClass ().getName ()));
191203 }
192- throw new IllegalArgumentException (
193- "Command '%s' not supported for light states" .formatted (command .getClass ().getName ()));
194204 }
195205
196206 /**
@@ -221,7 +231,7 @@ public void setBrightness(double brightness) throws IllegalArgumentException {
221231 * @param inceaseDecrease the increase/decrease command
222232 */
223233 private void setBrightness (IncreaseDecreaseType inceaseDecrease ) {
224- double brightness = Math .min (Math .max (cachedBrightness .doubleValue ()
234+ double brightness = Math .min (Math .max (cachedColor . getBrightness () .doubleValue ()
225235 + ((IncreaseDecreaseType .INCREASE == inceaseDecrease ? 1 : -1 ) * stepSize ), 0.0 ), 100.0 );
226236 setBrightness (brightness );
227237 }
@@ -280,6 +290,24 @@ private void setColorTemperature(QuantityType<?> colorTemperature) throws Illega
280290 }
281291 }
282292
293+ /**
294+ * Set the coolest color temperature in Mired
295+ *
296+ * @param coolestMired the coolest color temperature in Mired
297+ * @throws IllegalArgumentException if the coolestMired parameter is out of range or not less than warmestMired
298+ */
299+ public void setCoolestMired (double coolestMired ) throws IllegalArgumentException {
300+ if (coolestMired < 100.0 || coolestMired > 1000.0 ) {
301+ throw new IllegalArgumentException (
302+ "Coolest mired '%f' out of range [100.0..1000.0]" .formatted (coolestMired ));
303+ }
304+ if (warmestMired <= coolestMired ) {
305+ throw new IllegalArgumentException (
306+ "Warmest mired '%f' must be greater than coolest mired '%f'" .formatted (warmestMired , coolestMired ));
307+ }
308+ this .coolestMired = coolestMired ;
309+ }
310+
283311 /**
284312 * Update the hue from the remote light, ensuring it is in the range 0.0 to 360.0
285313 *
@@ -289,6 +317,33 @@ public void setHue(double hue) throws IllegalArgumentException {
289317 cachedColor = new HSBType (new DecimalType (hue ), cachedColor .getSaturation (), cachedColor .getBrightness ());
290318 }
291319
320+ /**
321+ * Set the step size for IncreaseDecreaseType commands
322+ *
323+ * @param stepSize the step size in percent
324+ * @throws IllegalArgumentException if the stepSize parameter is out of range
325+ */
326+ public void setIncreaseDecreaseStep (double stepSize ) throws IllegalArgumentException {
327+ if (stepSize < 1.0 || stepSize > 50.0 ) {
328+ throw new IllegalArgumentException ("Step size '%f' out of range (1.0..50.0]" .formatted (stepSize ));
329+ }
330+ this .stepSize = stepSize ;
331+ }
332+
333+ /**
334+ * Set the minimum brightness percent to consider as light "ON"
335+ *
336+ * @param minimumOnBrightness the minimum brightness percent
337+ * @throws IllegalArgumentException if the minimumBrightness parameter is out of range
338+ */
339+ public void setMinimumOnBrightness (double minimumOnBrightness ) throws IllegalArgumentException {
340+ if (minimumOnBrightness < 0.1 || minimumOnBrightness > 10.0 ) {
341+ throw new IllegalArgumentException (
342+ "Minimum brightness '%f' out of range [0.1..10.0]" .formatted (minimumOnBrightness ));
343+ }
344+ this .minimumOnBrightness = minimumOnBrightness ;
345+ }
346+
292347 /**
293348 * Update the mired color temperature from the remote light, and update the cached HSB color accordingly.
294349 * Constrain the mired value to be within the warmest and coolest limits.
@@ -335,19 +390,6 @@ public void setRGB(@Nullable Integer red, @Nullable Integer green, @Nullable Int
335390 cachedColor = new HSBType (hsb .getHue (), hsb .getSaturation (), cachedColor .getBrightness ());
336391 }
337392
338- /**
339- * Update the color with CIE XY fields from the remote light, and update the cached HSB color accordingly
340- *
341- * @param x the x field in range [0.0..1.0]
342- * @param y the y field in range [0.0..1.0]
343- *
344- * @throws IllegalArgumentException if any of the XY values are out of range [0.0..1.0]
345- */
346- public void setXY (double x , double y ) throws IllegalArgumentException {
347- HSBType hsb = ColorUtil .xyToHsb (new double [] { x , y });
348- cachedColor = new HSBType (hsb .getHue (), hsb .getSaturation (), cachedColor .getBrightness ());
349- }
350-
351393 /**
352394 * Update the saturation from the remote light, ensuring it is in the range 0.0 to 100.0
353395 *
@@ -357,101 +399,126 @@ public void setSaturation(double saturation) {
357399 cachedColor = new HSBType (cachedColor .getHue (), percentFrom (saturation ), cachedColor .getBrightness ());
358400 }
359401
360- /**
361- * Check if brightness control is supported
362- */
363- public boolean supportsBrightness () {
364- return supportsBrightness ;
365- }
366-
367- /**
368- * Check if color control is supported
369- */
370- public boolean supportsColor () {
371- return supportsColor ;
372- }
373-
374- /**
375- * Check if color temperature control is supported
376- */
377- public boolean supportsColorTemperature () {
378- return supportsColorTemperature ;
379- }
380-
381402 /**
382403 * Set whether brightness control is supported
383404 *
384405 * @param supportsBrightness true if brightness control is supported
385- * @return this LightStateMachine for method chaining
386406 */
387- public LightStateMachine withBrightness (boolean supportsBrightness ) {
407+ public void setSupportsBrightness (boolean supportsBrightness ) {
388408 this .supportsBrightness = supportsBrightness ;
389- return this ;
390409 }
391410
392411 /**
393412 * Set whether color control is supported
394413 *
395414 * @param supportsColor true if color control is supported
396- * @return this LightStateMachine for method chaining
397415 */
398- public LightStateMachine withColor (boolean supportsColor ) {
416+ public void setSupportsColor (boolean supportsColor ) {
399417 this .supportsColor = supportsColor ;
400- return this ;
401418 }
402419
403420 /**
404421 * Set whether color temperature control is supported
405422 *
406423 * @param supportsColorTemperature true if color temperature control is supported
407- * @return this LightStateMachine for method chaining
408424 */
409- public LightStateMachine withColorTemperature (boolean supportsColorTemperature ) {
425+ public void setSupportsColorTemperature (boolean supportsColorTemperature ) {
410426 this .supportsColorTemperature = supportsColorTemperature ;
411- return this ;
412427 }
413428
414429 /**
415- * Set the coolest color temperature in Mired
430+ * Set the warmest color temperature in Mired
416431 *
417- * @param coolestMired the coolest color temperature in Mired
418- * @return this LightStateMachine for method chaining
432+ * @param warmestMired the warmest color temperature in Mired
433+ *
434+ * @throws IllegalArgumentException if the warmestMired parameter is out of range or not greater than coolestMired
419435 */
420- public LightStateMachine withCoolestMired (double coolestMired ) {
421- this .coolestMired = coolestMired ;
422- return this ;
436+ public void setWarmestMired (double warmestMired ) throws IllegalArgumentException {
437+ if (warmestMired < 100.0 || warmestMired > 1000.0 ) {
438+ throw new IllegalArgumentException (
439+ "Warmest mired '%f' out of range [100.0..1000.0]" .formatted (warmestMired ));
440+ }
441+ if (warmestMired <= coolestMired ) {
442+ throw new IllegalArgumentException (
443+ "Warmest mired '%f' must be greater than coolest mired '%f'" .formatted (warmestMired , coolestMired ));
444+ }
445+ this .warmestMired = warmestMired ;
423446 }
424447
425448 /**
426- * Set the step size for IncreaseDecreaseType commands
449+ * Update the color with CIE XY fields from the remote light, and update the cached HSB color accordingly
427450 *
428- * @param stepSize the step size in percent
429- * @return this LightStateMachine for method chaining
451+ * @param x the x field in range [0.0..1.0]
452+ * @param y the y field in range [0.0..1.0]
453+ *
454+ * @throws IllegalArgumentException if any of the XY values are out of range [0.0..1.0]
430455 */
431- public LightStateMachine withIncreaseDecreaseStep (double stepSize ) {
432- this . stepSize = stepSize ;
433- return this ;
456+ public void setXY (double x , double y ) throws IllegalArgumentException {
457+ HSBType hsb = ColorUtil . xyToHsb ( new double [] { x , y }) ;
458+ cachedColor = new HSBType ( hsb . getHue (), hsb . getSaturation (), cachedColor . getBrightness ()) ;
434459 }
435460
436461 /**
437- * Set the minimum brightness percent to consider as light "ON"
438- *
439- * @param minimumBrightness the minimum brightness percent
440- * @return this LightStateMachine for method chaining
462+ * Check if brightness control is supported
441463 */
442- public LightStateMachine withMinimumBrightness (double minimumBrightness ) {
443- this .minimumOnBrightness = minimumBrightness ;
444- return this ;
464+ public boolean supportsBrightness () {
465+ return supportsBrightness ;
445466 }
446467
447468 /**
448- * Set the warmest color temperature in Mired
469+ * Check if color control is supported
470+ */
471+ public boolean supportsColor () {
472+ return supportsColor ;
473+ }
474+
475+ /**
476+ * Check if color temperature control is supported
477+ */
478+ public boolean supportsColorTemperature () {
479+ return supportsColorTemperature ;
480+ }
481+
482+ /**
483+ * Validate the parameters and throw IllegalArgumentException if any are out of range
449484 *
450- * @param warmestMired the warmest color temperature in Mired
451- * @return this LightStateMachine for method chaining
485+ * @throws IllegalArgumentException if any parameters are out of range
452486 */
453- public LightStateMachine withWarmestMired (double warmestMired ) {
454- this .warmestMired = warmestMired ;
455- return this ;
487+ private void validateParameters () throws IllegalArgumentException {
488+ if (minimumOnBrightness < 0.1 || minimumOnBrightness > 10.0 ) {
489+ throw new IllegalArgumentException (
490+ "Minimum brightness '%f' out of range [0.1..10.0]" .formatted (minimumOnBrightness ));
491+ }
492+ if (coolestMired < 100.0 || coolestMired > 1000.0 ) {
493+ throw new IllegalArgumentException (
494+ "Coolest mired '%f' out of range [100.0..1000.0]" .formatted (coolestMired ));
495+ }
496+ if (warmestMired < 100.0 || warmestMired > 1000.0 ) {
497+ throw new IllegalArgumentException (
498+ "Warmest mired '%f' out of range [100.0..1000.0]" .formatted (warmestMired ));
499+ }
500+ if (warmestMired <= coolestMired ) {
501+ throw new IllegalArgumentException (
502+ "Warmest mired '%f' must be greater than coolest mired '%f'" .formatted (warmestMired , coolestMired ));
503+ }
504+ if (stepSize < 1.0 || stepSize > 50.0 ) {
505+ throw new IllegalArgumentException ("Step size '%f' out of range (1.0..50.0]" .formatted (stepSize ));
506+ }
507+ }
508+
509+ public double getIncreaseDecreaseStep () {
510+ return stepSize ;
511+ }
512+
513+ public double getWarmestMired () {
514+ return warmestMired ;
515+ }
516+
517+ public double getCoolestMired () {
518+ return coolestMired ;
519+ }
520+
521+ public double getMinimumOnBrightness () {
522+ return minimumOnBrightness ;
456523 }
457524}
0 commit comments