import org.openhab.core.library.types.StringType;
import org.openhab.core.types.Command;
import org.openhab.core.types.UnDefType;
+import org.openhab.core.util.ColorUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
return String.format(formatPattern, hsbState.getHue().intValue(), hsbState.getSaturation().intValue(),
hsbState.getBrightness().intValue());
case RGB:
- PercentType[] rgb = hsbState.toRGB();
- return String.format(formatPattern, rgb[0].toBigDecimal().multiply(factor).intValue(),
- rgb[1].toBigDecimal().multiply(factor).intValue(),
- rgb[2].toBigDecimal().multiply(factor).intValue());
+ int[] rgb = ColorUtil.hsbToRgb(hsbState);
+ return String.format(formatPattern, rgb[0], rgb[1], rgb[2]);
case XYY:
- PercentType[] xyY = hsbState.toXY();
- return String.format(Locale.ROOT, formatPattern, xyY[0].floatValue() / 100.0f,
- xyY[1].floatValue() / 100.0f, hsbState.getBrightness().floatValue());
+ double[] xyY = ColorUtil.hsbToXY(hsbState);
+ return String.format(Locale.ROOT, formatPattern, xyY[0], xyY[1],
+ hsbState.getBrightness().doubleValue());
default:
throw new NotSupportedException(String.format("Non supported color mode: {}", this.colorMode));
}
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.number.IsCloseTo.closeTo;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.ArgumentMatchers.any;
import org.openhab.binding.mqtt.generic.values.TextValue;
import org.openhab.core.io.transport.mqtt.MqttBrokerConnection;
import org.openhab.core.library.types.HSBType;
+import org.openhab.core.library.types.PercentType;
import org.openhab.core.library.types.RawType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.library.unit.Units;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.types.Command;
+import org.openhab.core.util.ColorUtil;
/**
* Tests the {@link ChannelState} class.
c.processMessage("state", "ON".getBytes()); // Normal on state
assertThat(value.getChannelState().toString(), is("0,0,10"));
- assertThat(value.getMQTTpublishValue((Command) value.getChannelState(), null), is("25,25,25"));
+ assertThat(value.getMQTTpublishValue((Command) value.getChannelState(), null), is("26,26,26"));
c.processMessage("state", "FOFF".getBytes()); // Custom off state
assertThat(value.getChannelState().toString(), is("0,0,0"));
c.processMessage("state", "10".getBytes()); // Brightness only
assertThat(value.getChannelState().toString(), is("0,0,10"));
- assertThat(value.getMQTTpublishValue((Command) value.getChannelState(), null), is("25,25,25"));
+ assertThat(value.getMQTTpublishValue((Command) value.getChannelState(), null), is("26,26,26"));
HSBType t = HSBType.fromRGB(12, 18, 231);
c.processMessage("state", "12,18,231".getBytes());
assertThat(value.getChannelState(), is(t)); // HSB
- // rgb -> hsv -> rgb is quite lossy
- assertThat(value.getMQTTpublishValue((Command) value.getChannelState(), null), is("11,18,232"));
- assertThat(value.getMQTTpublishValue((Command) value.getChannelState(), "%3$d,%2$d,%1$d"), is("232,18,11"));
+ assertThat(value.getMQTTpublishValue((Command) value.getChannelState(), null), is("12,18,231"));
+ assertThat(value.getMQTTpublishValue((Command) value.getChannelState(), "%3$d,%2$d,%1$d"), is("231,18,12"));
}
@Test
ChannelState c = spy(new ChannelState(config, channelUIDMock, value, channelStateUpdateListenerMock));
c.start(connectionMock, mock(ScheduledExecutorService.class), 100);
+ // incoming messages
c.processMessage("state", "ON".getBytes()); // Normal on state
assertThat(value.getChannelState().toString(), is("0,0,10"));
- assertThat(value.getMQTTpublishValue((Command) value.getChannelState(), null), is("0.322700,0.329000,10.00"));
c.processMessage("state", "FOFF".getBytes()); // Custom off state
- assertThat(value.getChannelState().toString(), is("0,0,0"));
- assertThat(value.getMQTTpublishValue((Command) value.getChannelState(), null), is("0.000000,0.000000,0.00"));
+ // note we don't care what color value is currently stored, just that brightness is off
+ assertThat(((HSBType) value.getChannelState()).getBrightness(), is(PercentType.ZERO));
c.processMessage("state", "10".getBytes()); // Brightness only
assertThat(value.getChannelState().toString(), is("0,0,10"));
- assertThat(value.getMQTTpublishValue((Command) value.getChannelState(), null), is("0.322700,0.329000,10.00"));
-
- HSBType t = HSBType.fromXY(0.3f, 0.6f);
+ HSBType t = ColorUtil.xyToHsb(new double[] { 0.3f, 0.6f });
c.processMessage("state", "0.3,0.6,100".getBytes());
- assertThat(value.getChannelState(), is(t)); // HSB
- assertThat(value.getMQTTpublishValue((Command) value.getChannelState(), null), is("0.298700,0.601500,100.00"));
- assertThat(value.getMQTTpublishValue((Command) value.getChannelState(), "%3$.1f,%2$.4f,%1$.4f"),
- is("100.0,0.6015,0.2987"));
+ assertTrue(((HSBType) value.getChannelState()).closeTo(t, 0.001)); // HSB
+
+ // outgoing messages
+ // these use the 0.3,0.6,100 from above, but care more about proper formatting of the outgoing message
+ // than about the precise value (since color conversions have happened)
+ assertCloseTo(value.getMQTTpublishValue((Command) value.getChannelState(), null), "0.300000,0.600000,100.00");
+ assertCloseTo(value.getMQTTpublishValue((Command) value.getChannelState(), "%3$.1f,%2$.2f,%1$.2f"),
+ "100.0,0.60,0.30");
+ }
+
+ // also ensures the string elements are the same _length_, i.e. the correct precision for each element
+ private void assertCloseTo(String aString, String bString) {
+ String[] aElements = aString.split(",");
+ String[] bElements = bString.split(",");
+ double[] a = Arrays.stream(aElements).mapToDouble(Double::parseDouble).toArray();
+ double[] b = Arrays.stream(bElements).mapToDouble(Double::parseDouble).toArray();
+ for (int i = 0; i < a.length; i++) {
+ assertThat(aElements[i].length(), is(bElements[i].length()));
+ assertThat(a[i], closeTo(b[i], 0.002));
+ }
}
@Test
HSBType hsbType = color.getHSB();
assertNotNull(hsbType);
assertEquals(312, hsbType.getHue().intValue());
- assertEquals(92, hsbType.getSaturation().intValue());
+ assertEquals(91, hsbType.getSaturation().intValue());
assertEquals(100, hsbType.getBrightness().intValue());
}
assertEquals(84, (int) color.brightness);
HSBType hsbType = color.getHSB();
assertNotNull(hsbType);
- assertEquals(93, hsbType.getHue().intValue());
+ assertEquals(92, hsbType.getHue().intValue());
assertEquals(65, hsbType.getSaturation().intValue());
assertEquals(34, hsbType.getBrightness().intValue());
}
assertEquals(1, (int) color.brightness);
HSBType hsbType = color.getHSB();
assertNotNull(hsbType);
- assertEquals(93, hsbType.getHue().intValue());
+ assertEquals(92, hsbType.getHue().intValue());
assertEquals(65, hsbType.getSaturation().intValue());
assertEquals(1, hsbType.getBrightness().intValue());
}
HSBType hsbType = color.getHSB();
assertNotNull(hsbType);
assertEquals(156, hsbType.getHue().intValue());
- assertEquals(77, hsbType.getSaturation().intValue());
+ assertEquals(76, hsbType.getSaturation().intValue());
assertEquals(72, hsbType.getBrightness().intValue());
}