]> git.basschouten.com Git - openhab-addons.git/commitdiff
[mqtt][tradfri][webthing] Adapt to ColorUtil changes in core (#14810)
authorHolger Friedrich <holgerfriedrich@users.noreply.github.com>
Fri, 21 Apr 2023 21:55:36 +0000 (23:55 +0200)
committerGitHub <noreply@github.com>
Fri, 21 Apr 2023 21:55:36 +0000 (23:55 +0200)
* [mqtt][tradfri][webthing] Adapt to ColorUtil changes in core

Signed-off-by: Holger Friedrich <mail@holger-friedrich.de>
bundles/org.openhab.binding.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/values/ColorValue.java
bundles/org.openhab.binding.mqtt.generic/src/test/java/org/openhab/binding/mqtt/generic/ChannelStateTests.java
bundles/org.openhab.binding.mqtt.homeassistant/src/test/java/org/openhab/binding/mqtt/homeassistant/internal/component/AbstractComponentTests.java
bundles/org.openhab.binding.mqtt.homeassistant/src/test/java/org/openhab/binding/mqtt/homeassistant/internal/component/DefaultSchemaLightTests.java
bundles/org.openhab.binding.tradfri/src/test/java/org/openhab/binding/tradfri/internal/TradfriColorTest.java
bundles/org.openhab.binding.webthing/src/test/java/org/openhab/binding/webthing/internal/link/WebthingChannelLinkTest.java

index dc417582a0573b5d88c5235798ea70a48532428b..541c0e16f21f35d8fb7ad795d61d0a15465e3da1 100644 (file)
@@ -28,6 +28,7 @@ import org.openhab.core.library.types.PercentType;
 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;
 
@@ -144,14 +145,12 @@ public class ColorValue extends Value {
                 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));
         }
index 7cef112889048fb5211d11ab80313c4f93f155cd..52e1ae6d4ade4925a7226b6556770cc0ec3aa6e9 100644 (file)
@@ -14,6 +14,7 @@ package org.openhab.binding.mqtt.generic;
 
 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;
@@ -49,11 +50,13 @@ import org.openhab.binding.mqtt.generic.values.PercentageValue;
 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.
@@ -247,7 +250,7 @@ public class ChannelStateTests {
 
         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"));
@@ -255,15 +258,14 @@ public class ChannelStateTests {
 
         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
@@ -295,25 +297,39 @@ public class ChannelStateTests {
         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
index c14dee7af6d82c403c72ecabe41cc53a889b187b..fc5d8c3cf1369307a0be505345f003052da68e83 100644 (file)
@@ -41,6 +41,7 @@ import org.openhab.binding.mqtt.homeassistant.internal.HaID;
 import org.openhab.binding.mqtt.homeassistant.internal.HandlerConfiguration;
 import org.openhab.binding.mqtt.homeassistant.internal.config.dto.AbstractChannelConfiguration;
 import org.openhab.binding.mqtt.homeassistant.internal.handler.HomeAssistantThingHandler;
+import org.openhab.core.library.types.HSBType;
 import org.openhab.core.thing.Thing;
 import org.openhab.core.thing.ThingStatusInfo;
 import org.openhab.core.thing.binding.ThingHandlerCallback;
@@ -173,7 +174,12 @@ public abstract class AbstractComponentTests extends AbstractHomeAssistantTests
     @SuppressWarnings("null")
     protected static void assertState(AbstractComponent<@NonNull ? extends AbstractChannelConfiguration> component,
             String channelId, State state) {
-        assertThat(component.getChannel(channelId).getState().getCache().getChannelState(), is(state));
+        State actualState = component.getChannel(channelId).getState().getCache().getChannelState();
+        if ((actualState instanceof HSBType actualHsb) && (state instanceof HSBType stateHsb)) {
+            assertThat(actualHsb.closeTo(stateHsb, 0.01), is(true));
+        } else {
+            assertThat(actualState, is(state));
+        }
     }
 
     protected void spyOnChannelUpdates(AbstractComponent<@NonNull ? extends AbstractChannelConfiguration> component,
@@ -254,7 +260,7 @@ public abstract class AbstractComponentTests extends AbstractHomeAssistantTests
 
     /**
      * Send command to a thing's channel
-     * 
+     *
      * @param component component
      * @param channelId channel
      * @param command command to send
index 416c2cb71f841c13768ab65938a1aa212c3d64ee..7d1217fa4b20590eb4c787fa4ece79c1abe4a366 100644 (file)
@@ -137,7 +137,7 @@ public class DefaultSchemaLightTests extends AbstractComponentTests {
 
         // Brightness commands should route to the correct topic, converted to RGB
         sendCommand(component, Light.COLOR_CHANNEL_ID, new PercentType(50));
-        assertPublished("zigbee2mqtt/light/set/rgb", "127,127,127");
+        assertPublished("zigbee2mqtt/light/set/rgb", "128,128,128");
 
         // OnOff commands should route to the correct topic
         sendCommand(component, Light.COLOR_CHANNEL_ID, OnOffType.OFF);
index e1a7bf51bda07e97e8bf4f5872d0513762fc2327..c38f6344ab21cfe58dc92882172fc916571f61ee 100644 (file)
@@ -36,7 +36,7 @@ public class TradfriColorTest {
         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());
     }
 
@@ -48,7 +48,7 @@ public class TradfriColorTest {
         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());
     }
@@ -61,7 +61,7 @@ public class TradfriColorTest {
         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());
     }
@@ -75,7 +75,7 @@ public class TradfriColorTest {
         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());
     }
 
index 8d82a4a93cafd21f6bd96fb304e5f46420877f6b..476e27594aae4fe5dccce3d5cff68070bb850a09 100644 (file)
@@ -12,7 +12,7 @@
  */
 package org.openhab.binding.webthing.internal.link;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.*;
 import static org.mockito.Mockito.*;
 
 import java.net.URI;
@@ -185,7 +185,12 @@ public class WebthingChannelLinkTest {
         message.data = Map.of(propertyName, initialValue);
         websocketConnectionFactory.webSocketRef.get().sendToClient(message);
 
-        assertEquals(initialState, testWebthingThingHandler.itemState.get(channelUID));
+        Command actualState = testWebthingThingHandler.itemState.get(channelUID);
+        if ((actualState instanceof HSBType actualHsb) && (initialState instanceof HSBType initialStateHsb)) {
+            assertTrue(actualHsb.closeTo(initialStateHsb, 0.01));
+        } else {
+            assertEquals(initialState, actualState);
+        }
 
         ChannelToPropertyLink.establish(testWebthingThingHandler, channel, webthing, propertyName);
         testWebthingThingHandler.listeners.get(channelUID).onItemStateChanged(channelUID, updatedState);