Skip to content

Commit 5aab892

Browse files
committed
unit tests and refactoring
Signed-off-by: Andrew Fiddian-Green <software@whitebear.ch>
1 parent 875e6c7 commit 5aab892

2 files changed

Lines changed: 439 additions & 78 deletions

File tree

bundles/org.openhab.core/src/main/java/org/openhab/core/util/LightStateMachine.java

Lines changed: 145 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,13 @@
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

Comments
 (0)