From: Holger Friedrich Date: Fri, 26 Jan 2024 20:57:17 +0000 (+0100) Subject: [knx] Add support for RGBW represented by HSBType (#16078) X-Git-Url: https://git.basschouten.com/?a=commitdiff_plain;h=e68897c0a1c6d2912bf4ac3a8f8b468aa459acaf;p=openhab-addons.git [knx] Add support for RGBW represented by HSBType (#16078) Allow lossy conversion from RGBW to HSBType and back instead of using separate items for RGB and W. Select via DPT 251.60600. Signed-off-by: Holger Friedrich --- diff --git a/bundles/org.openhab.binding.knx/README.md b/bundles/org.openhab.binding.knx/README.md index fc0b764521..8012f3d278 100644 --- a/bundles/org.openhab.binding.knx/README.md +++ b/bundles/org.openhab.binding.knx/README.md @@ -6,7 +6,7 @@ Switching lights on and off, activating your roller shutters, or changing room t To access your KNX bus, you either need a gateway device which is connected to the KNX bus and allows computers to access the bus communication. This can be either an Ethernet (as a Router or a Tunnel type) or a serial gateway. The KNX binding then can communicate directly with this gateway. -Alternatively, a PC running [KNXD](https://github.com/knxd/knxd) (free open source component software) can be put in between which then acts as a broker allowing multiple client to connect to the same gateway. +Alternatively, a PC running [KNXD](https://github.com/knxd/knxd) (free open source component software) can be put in between which then acts as a broker allowing multiple clients to connect to the same gateway. Since the protocol is identical, the KNX binding can also communicate with it transparently. ***Attention:*** With the introduction of Unit of Measurement (UoM) support, some data types have changed (see `number` channel below): @@ -121,11 +121,17 @@ When a `GroupValueRead` telegram is sent from the KNX bus to a *-control Channel | position | Group address brightness | 5.001 | | increaseDecrease | Group address for relative brightness | 3.007 | -The `hsb` address supports DPT 242.600 and 251.600. +The `hsb` address supports DPT 232.600 (RGB), 242.600 (xyY), and 251.600 (RGBW). -Some RGB/RGBW products (e.g. MDT) support HSB values for DPT 232.600 instead of RGB. +Some RGB/RGBW products (e.g. MDT) use HSB values for DPT 232.600 instead of RGB. This is supported as "vendor-specific DPT" with a value of 232.60000. +RGBW (DPT 251.600) can either be converted to HSBType, or be represented two items: a HSBType for RGB and an additional PercentType for W channel. +Default handling for RGBW is to use separate items. +Note that this also requires two frames being sent out separately when these elements are sent to the bus, as the binary representation uses a partially populated KNX frame. +Alternatively, a single HSB item can be used. Conversion to a single HSBType will loose the exact setting for W, and will reconstruct it when a conversion to RGBW is required. +This option can be selected using the special DPT 251.60600. + ##### Channel Type `contact`, `contact-control` | Parameter | Description | Default DPT | diff --git a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/dpt/DPTUtil.java b/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/dpt/DPTUtil.java index 96fb13676a..c3c7479e37 100644 --- a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/dpt/DPTUtil.java +++ b/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/dpt/DPTUtil.java @@ -55,7 +55,7 @@ public class DPTUtil { // used to map vendor-specific data to standard DPT public static final Map NORMALIZED_DPT = Map.of(// - "232.60000", "232.600"); + "232.60000", "232.600", "251.60600", "251.600"); // fall back if no specific type is defined in DPT_TYPE_MAP private static final Map>> DPT_MAIN_TYPE_MAP = Map.ofEntries( // diff --git a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/dpt/ValueDecoder.java b/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/dpt/ValueDecoder.java index 85c7d4337a..8d6b33550c 100644 --- a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/dpt/ValueDecoder.java +++ b/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/dpt/ValueDecoder.java @@ -208,7 +208,7 @@ public class ValueDecoder { case "242": return handleDpt242(value); case "251": - return handleDpt251(value, preferredType); + return handleDpt251(value, subType, preferredType); default: return handleNumericDpt(id, translator, preferredType); // TODO 6.001 is mapped to PercentType, which can only cover 0-100%, not -128..127% @@ -418,7 +418,7 @@ public class ValueDecoder { return null; } - private static @Nullable Type handleDpt251(String value, Class preferredType) { + private static @Nullable Type handleDpt251(String value, String subType, Class preferredType) { Matcher rgbw = RGBW_PATTERN.matcher(value); if (rgbw.matches()) { String rString = rgbw.group("r"); @@ -426,19 +426,39 @@ public class ValueDecoder { String bString = rgbw.group("b"); String wString = rgbw.group("w"); - if (rString != null && gString != null && bString != null && HSBType.class.equals(preferredType)) { - // does not support PercentType and r,g,b valid -> HSBType - int r = coerceToRange((int) (Double.parseDouble(rString.replace(",", ".")) * 2.55), 0, 255); - int g = coerceToRange((int) (Double.parseDouble(gString.replace(",", ".")) * 2.55), 0, 255); - int b = coerceToRange((int) (Double.parseDouble(bString.replace(",", ".")) * 2.55), 0, 255); - - return HSBType.fromRGB(r, g, b); - } else if (wString != null && PercentType.class.equals(preferredType)) { - // does support PercentType and w valid -> PercentType - BigDecimal w = new BigDecimal(wString.replace(",", ".")); - - return new PercentType(w); + switch (subType) { + case "600": + if (rString != null && gString != null && bString != null && HSBType.class.equals(preferredType)) { + // does not support PercentType and r,g,b valid -> HSBType + int r = coerceToRange((int) (Double.parseDouble(rString.replace(",", ".")) * 2.55), 0, 255); + int g = coerceToRange((int) (Double.parseDouble(gString.replace(",", ".")) * 2.55), 0, 255); + int b = coerceToRange((int) (Double.parseDouble(bString.replace(",", ".")) * 2.55), 0, 255); + + return HSBType.fromRGB(r, g, b); + } else if (wString != null && PercentType.class.equals(preferredType)) { + // does support PercentType and w valid -> PercentType + BigDecimal w = new BigDecimal(wString.replace(",", ".")); + + return new PercentType(w); + } + case "60600": + // special type used by OH for .600 indicating that RGBW should be handled with a single HSBType, + // typically we use HSBType for RGB and PercentType for W. + if (rString != null && gString != null && bString != null && wString != null + && HSBType.class.equals(preferredType)) { + // does support PercentType and w valid -> PercentType + int r = coerceToRange((int) (Double.parseDouble(rString.replace(",", ".")) * 2.55), 0, 255); + int g = coerceToRange((int) (Double.parseDouble(gString.replace(",", ".")) * 2.55), 0, 255); + int b = coerceToRange((int) (Double.parseDouble(bString.replace(",", ".")) * 2.55), 0, 255); + int w = coerceToRange((int) (Double.parseDouble(wString.replace(",", ".")) * 2.55), 0, 255); + + return ColorUtil.rgbToHsb(new int[] { r, g, b, w }); + } + default: + LOGGER.warn("Unknown subtype '251.{}', no conversion possible.", subType); + return null; } + } LOGGER.warn("Failed to convert '{}' (DPT 251): Pattern does not match or invalid content", value); return null; diff --git a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/dpt/ValueEncoder.java b/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/dpt/ValueEncoder.java index cbf5de4bab..f2768a7b83 100644 --- a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/dpt/ValueEncoder.java +++ b/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/dpt/ValueEncoder.java @@ -171,6 +171,10 @@ public class ValueEncoder { PercentType[] rgbw = ColorUtil.hsbToRgbPercent(hsb); return String.format("%,.1f %,.1f %,.1f - %%", rgbw[0].doubleValue(), rgbw[1].doubleValue(), rgbw[2].doubleValue()); + case "251.60600": + PercentType[] rgbw2 = ColorUtil.hsbToRgbwPercent(hsb); + return String.format("%,.1f %,.1f %,.1f %,.1f %%", rgbw2[0].doubleValue(), rgbw2[1].doubleValue(), + rgbw2[2].doubleValue(), rgbw2[3].doubleValue()); case "5.003": return hsb.getHue().toString(); default: diff --git a/bundles/org.openhab.binding.knx/src/test/java/org/openhab/binding/knx/internal/itests/Back2BackTest.java b/bundles/org.openhab.binding.knx/src/test/java/org/openhab/binding/knx/internal/itests/Back2BackTest.java index 8049904003..36a57a5169 100644 --- a/bundles/org.openhab.binding.knx/src/test/java/org/openhab/binding/knx/internal/itests/Back2BackTest.java +++ b/bundles/org.openhab.binding.knx/src/test/java/org/openhab/binding/knx/internal/itests/Back2BackTest.java @@ -582,6 +582,16 @@ public class Back2BackTest { // RGBW, only RGB part helper("251.600", new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, 0x00, 0x00, 0x0e }, new HSBType("0, 0, 100"), new byte[] { 1, 1, 1, 0, 0, 0 }, new byte[0]); + // RGBW, only W part + helper("251.600", new byte[] { 0x0, 0x0, 0x0, 0x1A, 0x00, 0x01 }, new PercentType("10.2")); + // RGBW, all + helper("251.60600", new byte[] { (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xff, 0x00, 0x0f }, + new HSBType("0, 0, 100"), new byte[] { 1, 1, 1, 2, 0, 0 }, new byte[0]); + // RGBW, mixed + int[] rgbw = new int[] { 240, 0x0, 0x0, 0x0f }; + HSBType hsb = ColorUtil.rgbToHsb(rgbw); + helper("251.60600", new byte[] { (byte) rgbw[0], (byte) rgbw[1], (byte) rgbw[2], (byte) rgbw[3], 0x00, 0x0f }, + hsb, new byte[] { 2, 2, 2, 2, 0, 0 }, new byte[0]); } @Test