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):
| 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 |
// used to map vendor-specific data to standard DPT
public static final Map<String, String> 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<String, Set<Class<? extends Type>>> DPT_MAIN_TYPE_MAP = Map.ofEntries( //
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%
return null;
}
- private static @Nullable Type handleDpt251(String value, Class<? extends Type> preferredType) {
+ private static @Nullable Type handleDpt251(String value, String subType, Class<? extends Type> preferredType) {
Matcher rgbw = RGBW_PATTERN.matcher(value);
if (rgbw.matches()) {
String rString = rgbw.group("r");
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;
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:
// 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