From 4e2d87da5c9598e4c5e403bf05026eb1b5aabf7c Mon Sep 17 00:00:00 2001 From: Sebastian P <5564491+s3lph@users.noreply.github.com> Date: Fri, 1 Jul 2022 08:11:00 +0200 Subject: [PATCH] [dali] Implement DT8 (single-channel RGB & color temperature) device type (#12955) * DALI: Implement DT8 (single-channel RGB & color temperature) device type, fix device and group addressing * dali: Store BridgeHandler in a local variable instead of retrieving it over and over again. * dali: Follow logging guidelines. Signed-off-by: Sebastian Philipp --- bundles/org.openhab.binding.dali/README.md | 24 ++- .../dali/internal/DaliBindingConstants.java | 9 +- .../dali/internal/DaliHandlerFactory.java | 4 + .../internal/handler/DaliDeviceHandler.java | 27 ++- .../handler/DaliDt8DeviceHandler.java | 187 ++++++++++++++++++ .../handler/DaliserverBridgeHandler.java | 3 +- .../dali/internal/protocol/DaliAddress.java | 25 ++- .../protocol/DaliStandardCommand.java | 40 ++++ .../resources/OH-INF/i18n/dali.properties | 6 + .../resources/OH-INF/thing/thing-types.xml | 55 ++++++ 10 files changed, 363 insertions(+), 17 deletions(-) create mode 100644 bundles/org.openhab.binding.dali/src/main/java/org/openhab/binding/dali/internal/handler/DaliDt8DeviceHandler.java diff --git a/bundles/org.openhab.binding.dali/README.md b/bundles/org.openhab.binding.dali/README.md index 2c89809c0f2..ebbd159ece1 100644 --- a/bundles/org.openhab.binding.dali/README.md +++ b/bundles/org.openhab.binding.dali/README.md @@ -13,6 +13,8 @@ Currently, these things are supported: - device (single device/ballast on the DALI bus) - group (group of DALI devices) - rgb (virtual device consisting of three directly addressed devices that represent r/g/b (LED) color channels) + - device-dt8 (single device/ballast supporting DT8 (single-channel RGB & color temperature control)) + - group-dt8 (group of DALI devices supporting DT8) This binding was tested on a DALI 1 bus with daliserver 0.2. @@ -37,9 +39,10 @@ Automatic device discovery is not yet implemented. ### group -| Parameter | Parameter ID | Required/Optional | description | -|-------------|--------------|-------------------|----------------------------------------| -| Group ID | targetId | Required | Address of group in the DALI bus | +| Parameter | Parameter ID | Required/Optional | description | +|----------------|--------------------|-------------------|----------------------------------------------------------------------------------------------| +| Group ID | targetId | Required | Address of group in the DALI bus | +| Read Device ID | readDeviceTargetId | Optional | If reading values from this group fails, you can choose to read from a single device instead | ### rgb @@ -49,6 +52,19 @@ Automatic device discovery is not yet implemented. | G Device ID | targetIdG | Required | Address of device in the DALI bus | | B Device ID | targetIdB | Required | Address of device in the DALI bus | +### device-dt8 + +| Parameter | Parameter ID | Required/Optional | description | +|-------------|--------------|-------------------|----------------------------------------| +| Device ID | targetId | Required | Address of device in the DALI bus | + +### group-dt8 + +| Parameter | Parameter ID | Required/Optional | description | +|----------------|--------------------|-------------------|----------------------------------------------------------------------------------------------| +| Group ID | targetId | Required | Address of group in the DALI bus | +| Read Device ID | readDeviceTargetId | Optional | If reading values from this group fails, you can choose to read from a single device instead | + ## Full Example .things file @@ -57,7 +73,7 @@ Automatic device discovery is not yet implemented. Bridge dali:daliserver:237dbae7 "Daliserver" [ host="localhost", port=55825] { Thing rgb 87bf0403-a45d-4037-b874-28f4ece30004 "RGB Lights" [ targetIdR=0, targetIdG=1, targetIdB=2 ] Thing device 995e16ca-07c4-4111-9cda-504cb5120f82 "Warm White" [ targetId=3 ] - Thing group 31da8dac-8e09-455a-bc7a-6ed70f740001 "Living Room Lights" [ targetId=0 ] + Thing group 31da8dac-8e09-455a-bc7a-6ed70f740001 "Living Room Lights" [ targetId=0, readDeviceTargetId=3 ] } ``` diff --git a/bundles/org.openhab.binding.dali/src/main/java/org/openhab/binding/dali/internal/DaliBindingConstants.java b/bundles/org.openhab.binding.dali/src/main/java/org/openhab/binding/dali/internal/DaliBindingConstants.java index 2b3a35c1600..de0cce92e5c 100644 --- a/bundles/org.openhab.binding.dali/src/main/java/org/openhab/binding/dali/internal/DaliBindingConstants.java +++ b/bundles/org.openhab.binding.dali/src/main/java/org/openhab/binding/dali/internal/DaliBindingConstants.java @@ -35,15 +35,18 @@ public class DaliBindingConstants { public static final ThingTypeUID THING_TYPE_DEVICE = new ThingTypeUID(BINDING_ID, "device"); public static final ThingTypeUID THING_TYPE_GROUP = new ThingTypeUID(BINDING_ID, "group"); public static final ThingTypeUID THING_TYPE_RGB = new ThingTypeUID(BINDING_ID, "rgb"); - - public static final Set SUPPORTED_DEVICE_THING_TYPES_UIDS = new HashSet<>( - Arrays.asList(THING_TYPE_DEVICE, THING_TYPE_GROUP, THING_TYPE_RGB)); + public static final ThingTypeUID THING_TYPE_DEVICE_DT8 = new ThingTypeUID(BINDING_ID, "device-dt8"); + public static final ThingTypeUID THING_TYPE_GROUP_DT8 = new ThingTypeUID(BINDING_ID, "group-dt8"); + public static final Set SUPPORTED_DEVICE_THING_TYPES_UIDS = new HashSet<>(Arrays + .asList(THING_TYPE_DEVICE, THING_TYPE_GROUP, THING_TYPE_RGB, THING_TYPE_DEVICE_DT8, THING_TYPE_GROUP_DT8)); public static final String CHANNEL_DIM_AT_FADE_RATE = "dimAtFadeRate"; public static final String CHANNEL_DIM_IMMEDIATELY = "dimImmediately"; public static final String CHANNEL_COLOR = "color"; + public static final String CHANNEL_COLOR_TEMPERATURE = "color-temperature-abs"; public static final String TARGET_ID = "targetId"; + public static final String READ_DEVICE_TARGET_ID = "readDeviceTargetId"; public static final String TARGET_ID_R = "targetIdR"; public static final String TARGET_ID_G = "targetIdG"; public static final String TARGET_ID_B = "targetIdB"; diff --git a/bundles/org.openhab.binding.dali/src/main/java/org/openhab/binding/dali/internal/DaliHandlerFactory.java b/bundles/org.openhab.binding.dali/src/main/java/org/openhab/binding/dali/internal/DaliHandlerFactory.java index 9f3b358a4fb..e75b04fd8c0 100644 --- a/bundles/org.openhab.binding.dali/src/main/java/org/openhab/binding/dali/internal/DaliHandlerFactory.java +++ b/bundles/org.openhab.binding.dali/src/main/java/org/openhab/binding/dali/internal/DaliHandlerFactory.java @@ -21,6 +21,7 @@ import java.util.stream.Stream; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.dali.internal.handler.DaliDeviceHandler; +import org.openhab.binding.dali.internal.handler.DaliDt8DeviceHandler; import org.openhab.binding.dali.internal.handler.DaliRgbHandler; import org.openhab.binding.dali.internal.handler.DaliserverBridgeHandler; import org.openhab.core.thing.Bridge; @@ -64,6 +65,9 @@ public class DaliHandlerFactory extends BaseThingHandlerFactory { if (THING_TYPE_RGB.equals(thingTypeUID)) { return new DaliRgbHandler(thing); } + if (THING_TYPE_DEVICE_DT8.equals(thingTypeUID) || THING_TYPE_GROUP_DT8.equals(thingTypeUID)) { + return new DaliDt8DeviceHandler(thing); + } return null; } diff --git a/bundles/org.openhab.binding.dali/src/main/java/org/openhab/binding/dali/internal/handler/DaliDeviceHandler.java b/bundles/org.openhab.binding.dali/src/main/java/org/openhab/binding/dali/internal/handler/DaliDeviceHandler.java index d531df1fc7b..c371fd10844 100644 --- a/bundles/org.openhab.binding.dali/src/main/java/org/openhab/binding/dali/internal/handler/DaliDeviceHandler.java +++ b/bundles/org.openhab.binding.dali/src/main/java/org/openhab/binding/dali/internal/handler/DaliDeviceHandler.java @@ -22,6 +22,7 @@ import org.openhab.binding.dali.internal.protocol.DaliAddress; import org.openhab.binding.dali.internal.protocol.DaliDAPCCommand; import org.openhab.binding.dali.internal.protocol.DaliResponse; import org.openhab.binding.dali.internal.protocol.DaliStandardCommand; +import org.openhab.core.config.core.Configuration; import org.openhab.core.library.types.IncreaseDecreaseType; import org.openhab.core.library.types.OnOffType; import org.openhab.core.library.types.PercentType; @@ -45,7 +46,8 @@ import org.slf4j.LoggerFactory; @NonNullByDefault public class DaliDeviceHandler extends BaseThingHandler { private final Logger logger = LoggerFactory.getLogger(DaliDeviceHandler.class); - private @Nullable Integer targetId; + protected @Nullable Integer targetId; + protected @Nullable Integer readDeviceTargetId; public DaliDeviceHandler(Thing thing) { super(thing); @@ -61,7 +63,16 @@ public class DaliDeviceHandler extends BaseThingHandler { updateStatus(ThingStatus.ONLINE); } - targetId = ((BigDecimal) this.thing.getConfiguration().get(TARGET_ID)).intValueExact(); + final Configuration conf = this.thing.getConfiguration(); + targetId = ((BigDecimal) conf.get(TARGET_ID)).intValueExact(); + // Reading from group addresses does not work generally, so if a fallback device id is + // defined, use that instead when reading the current state + if (conf.get(READ_DEVICE_TARGET_ID) != null) { + readDeviceTargetId = ((BigDecimal) this.thing.getConfiguration().get(READ_DEVICE_TARGET_ID)) + .intValueExact(); + } else { + readDeviceTargetId = null; + } } @Override @@ -70,9 +81,11 @@ public class DaliDeviceHandler extends BaseThingHandler { if (CHANNEL_DIM_AT_FADE_RATE.equals(channelUID.getId()) || CHANNEL_DIM_IMMEDIATELY.equals(channelUID.getId())) { DaliAddress address; - if (THING_TYPE_DEVICE.equals(this.thing.getThingTypeUID())) { + if (THING_TYPE_DEVICE.equals(this.thing.getThingTypeUID()) + || THING_TYPE_DEVICE_DT8.equals(this.thing.getThingTypeUID())) { address = DaliAddress.createShortAddress(targetId); - } else if (THING_TYPE_GROUP.equals(this.thing.getThingTypeUID())) { + } else if (THING_TYPE_GROUP.equals(this.thing.getThingTypeUID()) + || THING_TYPE_GROUP_DT8.equals(this.thing.getThingTypeUID())) { address = DaliAddress.createGroupAddress(targetId); } else { throw new DaliException("unknown device type"); @@ -110,8 +123,12 @@ public class DaliDeviceHandler extends BaseThingHandler { } if (queryDeviceState) { + DaliAddress readAddress = address; + if (readDeviceTargetId != null) { + readAddress = DaliAddress.createShortAddress(readDeviceTargetId); + } getBridgeHandler() - .sendCommandWithResponse(DaliStandardCommand.createQueryActualLevelCommand(address), + .sendCommandWithResponse(DaliStandardCommand.createQueryActualLevelCommand(readAddress), DaliResponse.NumericMask.class) .thenAccept(response -> { if (response != null && !response.mask) { diff --git a/bundles/org.openhab.binding.dali/src/main/java/org/openhab/binding/dali/internal/handler/DaliDt8DeviceHandler.java b/bundles/org.openhab.binding.dali/src/main/java/org/openhab/binding/dali/internal/handler/DaliDt8DeviceHandler.java new file mode 100644 index 00000000000..d9111615d44 --- /dev/null +++ b/bundles/org.openhab.binding.dali/src/main/java/org/openhab/binding/dali/internal/handler/DaliDt8DeviceHandler.java @@ -0,0 +1,187 @@ +/** + * Copyright (c) 2010-2022 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.dali.internal.handler; + +import static org.openhab.binding.dali.internal.DaliBindingConstants.CHANNEL_COLOR; +import static org.openhab.binding.dali.internal.DaliBindingConstants.CHANNEL_COLOR_TEMPERATURE; +import static org.openhab.binding.dali.internal.DaliBindingConstants.THING_TYPE_DEVICE_DT8; +import static org.openhab.binding.dali.internal.DaliBindingConstants.THING_TYPE_GROUP_DT8; + +import java.util.concurrent.CompletableFuture; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.dali.internal.protocol.DaliAddress; +import org.openhab.binding.dali.internal.protocol.DaliResponse; +import org.openhab.binding.dali.internal.protocol.DaliResponse.NumericMask; +import org.openhab.binding.dali.internal.protocol.DaliStandardCommand; +import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.types.HSBType; +import org.openhab.core.library.types.PercentType; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingStatus; +import org.openhab.core.thing.ThingStatusDetail; +import org.openhab.core.types.Command; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link DaliDeviceHandler} handles commands for things of type Device and Group. + * + * @author Robert Schmid - Initial contribution + */ +@NonNullByDefault +public class DaliDt8DeviceHandler extends DaliDeviceHandler { + private final Logger logger = LoggerFactory.getLogger(DaliDt8DeviceHandler.class); + + public DaliDt8DeviceHandler(Thing thing) { + super(thing); + } + + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + try { + final DaliserverBridgeHandler daliHandler = getBridgeHandler(); + if (CHANNEL_COLOR_TEMPERATURE.equals(channelUID.getId())) { + DaliAddress address; + if (THING_TYPE_DEVICE_DT8.equals(this.thing.getThingTypeUID())) { + address = DaliAddress.createShortAddress(targetId); + } else if (THING_TYPE_GROUP_DT8.equals(this.thing.getThingTypeUID())) { + address = DaliAddress.createGroupAddress(targetId); + } else { + throw new DaliException("unknown device type"); + } + if (command instanceof DecimalType) { + // Color temperature in DALI is represented in mirek ("reciprocal megakelvin") + // It is one million times the reciprocal of the color temperature (in Kelvin) + final int mirek = (int) (1E6f + / (Math.min(Math.max(((DecimalType) command).intValue(), 1000), 20000))); + final byte mirekLsb = (byte) (mirek & 0xff); + final byte mirekMsb = (byte) ((mirek >> 8) & 0xff); + // Write mirek value to the DTR0+DTR1 registers + daliHandler.sendCommand(DaliStandardCommand.createSetDTR0Command(mirekLsb)); + daliHandler.sendCommand(DaliStandardCommand.createSetDTR1Command(mirekMsb)); + // Indicate that the follwing command is a DT8 (WW/CW and single-channel RGB) command + daliHandler.sendCommand(DaliStandardCommand.createSetDeviceTypeCommand(8)); + // Set the color temperature to the value in DTR0+DTR1 + daliHandler.sendCommand(DaliStandardCommand.createSetColorTemperatureCommand(address)); + // Finish the command sequence + daliHandler.sendCommand(DaliStandardCommand.createSetDeviceTypeCommand(8)); + daliHandler.sendCommand(DaliStandardCommand.createActivateCommand(address)); + + } + + DaliAddress readAddress = address; + if (readDeviceTargetId != null) { + readAddress = DaliAddress.createShortAddress(readDeviceTargetId); + } + // Write argument 0x02 (query color temperature) to DTR0 and set DT8 + daliHandler.sendCommand(DaliStandardCommand.createSetDTR0Command(2)); + daliHandler.sendCommand(DaliStandardCommand.createSetDeviceTypeCommand(8)); + // Mirek MSB is returned as result + CompletableFuture<@Nullable NumericMask> responseMsb = daliHandler.sendCommandWithResponse( + DaliStandardCommand.createQueryColorValueCommand(readAddress), DaliResponse.NumericMask.class); + daliHandler.sendCommand(DaliStandardCommand.createSetDeviceTypeCommand(8)); + // Mirek LSB is written to DTR0 + CompletableFuture<@Nullable NumericMask> responseLsb = daliHandler.sendCommandWithResponse( + DaliStandardCommand.createQueryContentDTR0Command(readAddress), DaliResponse.NumericMask.class); + + CompletableFuture.allOf(responseMsb, responseLsb).thenAccept(x -> { + @Nullable + NumericMask msb = responseMsb.join(), lsb = responseLsb.join(); + if (msb != null && !msb.mask && lsb != null && !lsb.mask) { + final int msbValue = msb.value != null ? msb.value : 0; + final int lsbValue = lsb.value != null ? lsb.value : 0; + final int mirek = ((msbValue & 0xff) << 8) | (lsbValue & 0xff); + final int kelvin = (int) (1E6f / mirek); + updateState(channelUID, new DecimalType(kelvin)); + } + }).exceptionally(e -> { + logger.warn("Error querying device status: {}", e.getMessage()); + return null; + }); + + } else if (CHANNEL_COLOR.equals(channelUID.getId())) { + DaliAddress address; + if (THING_TYPE_DEVICE_DT8.equals(this.thing.getThingTypeUID())) { + address = DaliAddress.createShortAddress(targetId); + } else if (THING_TYPE_GROUP_DT8.equals(this.thing.getThingTypeUID())) { + address = DaliAddress.createGroupAddress(targetId); + } else { + throw new DaliException("unknown device type"); + } + if (command instanceof HSBType) { + PercentType[] rgb = ((HSBType) command).toRGB(); + final int r = (int) (254 * (rgb[0].floatValue() / 100)); + final int g = (int) (254 * (rgb[1].floatValue() / 100)); + final int b = (int) (254 * (rgb[2].floatValue() / 100)); + logger.trace("RGB: {} {} {}", r, g, b); + // Write RGB values to the DTR0+DTR1+DTR2 registers + daliHandler.sendCommand(DaliStandardCommand.createSetDTR0Command(r)); + daliHandler.sendCommand(DaliStandardCommand.createSetDTR1Command(g)); + daliHandler.sendCommand(DaliStandardCommand.createSetDTR2Command(b)); + // Indicate that the following command is a DT8 (WW/CW and single-channel RGB) command + daliHandler.sendCommand(DaliStandardCommand.createSetDeviceTypeCommand(8)); + // Set the color to the values in DTR0+DTR1+DTR2 + daliHandler.sendCommand(DaliStandardCommand.createSetRgbDimlevelCommand(address)); + // Finish the command sequence + daliHandler.sendCommand(DaliStandardCommand.createSetDeviceTypeCommand(8)); + daliHandler.sendCommand(DaliStandardCommand.createActivateCommand(address)); + } + + DaliAddress readAddress = address; + if (readDeviceTargetId != null) { + readAddress = DaliAddress.createShortAddress(readDeviceTargetId); + } + // Write argument 0xE9 (query red dimlevel) to DTR0 and set DT8 + daliHandler.sendCommand(DaliStandardCommand.createSetDTR0Command(0xe9)); + daliHandler.sendCommand(DaliStandardCommand.createSetDeviceTypeCommand(8)); + // Red component is returned as result + CompletableFuture<@Nullable NumericMask> responseRed = daliHandler.sendCommandWithResponse( + DaliStandardCommand.createQueryColorValueCommand(readAddress), DaliResponse.NumericMask.class); + // Write argument 0xEA (query green dimlevel) to DTR0 and set DT8 + daliHandler.sendCommand(DaliStandardCommand.createSetDTR0Command(0xea)); + daliHandler.sendCommand(DaliStandardCommand.createSetDeviceTypeCommand(8)); + // Green component is returned as result + CompletableFuture<@Nullable NumericMask> responseGreen = daliHandler.sendCommandWithResponse( + DaliStandardCommand.createQueryColorValueCommand(readAddress), DaliResponse.NumericMask.class); + // Write argument 0xEB (query blue dimlevel) to DTR0 and set DT8 + daliHandler.sendCommand(DaliStandardCommand.createSetDTR0Command(0xeb)); + daliHandler.sendCommand(DaliStandardCommand.createSetDeviceTypeCommand(8)); + // Blue component is returned as result + CompletableFuture<@Nullable NumericMask> responseBlue = daliHandler.sendCommandWithResponse( + DaliStandardCommand.createQueryColorValueCommand(readAddress), DaliResponse.NumericMask.class); + + CompletableFuture.allOf(responseRed, responseGreen, responseBlue).thenAccept(x -> { + @Nullable + NumericMask r = responseRed.join(), g = responseGreen.join(), b = responseBlue.join(); + if (r != null && !r.mask && g != null && !g.mask && b != null && !b.mask) { + final int rValue = r.value != null ? r.value : 0; + final int gValue = g.value != null ? g.value : 0; + final int bValue = b.value != null ? b.value : 0; + updateState(channelUID, HSBType.fromRGB(rValue, gValue, bValue)); + } + }).exceptionally(e -> { + logger.warn("Error querying device status: {}", e.getMessage()); + return null; + }); + + } else { + super.handleCommand(channelUID, command); + } + } catch (DaliException e) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage()); + } + } +} diff --git a/bundles/org.openhab.binding.dali/src/main/java/org/openhab/binding/dali/internal/handler/DaliserverBridgeHandler.java b/bundles/org.openhab.binding.dali/src/main/java/org/openhab/binding/dali/internal/handler/DaliserverBridgeHandler.java index 7fdf593f986..8818ea76378 100644 --- a/bundles/org.openhab.binding.dali/src/main/java/org/openhab/binding/dali/internal/handler/DaliserverBridgeHandler.java +++ b/bundles/org.openhab.binding.dali/src/main/java/org/openhab/binding/dali/internal/handler/DaliserverBridgeHandler.java @@ -142,6 +142,7 @@ public class DaliserverBridgeHandler extends BaseBridgeHandler { } catch (Exception e) { logger.warn("Unexpected exception while sending command to daliserver: {} Message: {}", frame, e.getMessage()); + logger.trace("Stacktrace", e); future.completeExceptionally(e); } }); @@ -161,7 +162,7 @@ public class DaliserverBridgeHandler extends BaseBridgeHandler { } byte status = response[1], rval = response[2]; if (status == 0) { - result.parse(null); + // No return value to process. } else if (status == 1) { result.parse(new DaliBackwardFrame(rval)); } else if (status == 255) { diff --git a/bundles/org.openhab.binding.dali/src/main/java/org/openhab/binding/dali/internal/protocol/DaliAddress.java b/bundles/org.openhab.binding.dali/src/main/java/org/openhab/binding/dali/internal/protocol/DaliAddress.java index 18ae68b05a5..c3494917b5b 100644 --- a/bundles/org.openhab.binding.dali/src/main/java/org/openhab/binding/dali/internal/protocol/DaliAddress.java +++ b/bundles/org.openhab.binding.dali/src/main/java/org/openhab/binding/dali/internal/protocol/DaliAddress.java @@ -36,10 +36,27 @@ public abstract class DaliAddress { protected T addToFrame(T frame) throws DaliException { if (frame.length() == 16) { frame.data &= ~(1 << 15); // unset bit 15 - frame.data |= ((address & 0b11111) << 9); + frame.data |= ((address & 0b111111) << 9); } else if (frame.length() == 24) { frame.data &= ~(1 << 23); // unset bit 23 - frame.data |= ((address & 0b11111) << 17); + frame.data |= ((address & 0b111111) << 17); + } else { + throw new DaliException("Unsupported frame size"); + } + return frame; + } + }; + } + + static DaliAddress createRawAddress(int address) { + return new DaliAddress() { + @Override + protected T addToFrame(T frame) throws DaliException { + // Keep all bits of the raw address + if (frame.length() == 16) { + frame.data |= ((address & 0xff) << 8); + } else if (frame.length() == 24) { + frame.data |= ((address & 0xff) << 16); } else { throw new DaliException("Unsupported frame size"); } @@ -91,9 +108,9 @@ public abstract class DaliAddress { if (address > 15) { throw new DaliException("Groups 16..31 are not supported in 16-bit forward frames"); } - frame.data |= ((0x4 << 3) & (address & 0b111)) << 9; + frame.data |= (0x80 | ((address & 0b1111) << 1)) << 8; } else if (frame.length() == 24) { - frame.data |= ((0x2 << 4) & (address & 0b1111)) << 17; + frame.data |= (0x80 | ((address & 0b11111) << 1)) << 16; } else { throw new DaliException("Unsupported frame size"); } diff --git a/bundles/org.openhab.binding.dali/src/main/java/org/openhab/binding/dali/internal/protocol/DaliStandardCommand.java b/bundles/org.openhab.binding.dali/src/main/java/org/openhab/binding/dali/internal/protocol/DaliStandardCommand.java index c239b0911ee..aa7362543f3 100644 --- a/bundles/org.openhab.binding.dali/src/main/java/org/openhab/binding/dali/internal/protocol/DaliStandardCommand.java +++ b/bundles/org.openhab.binding.dali/src/main/java/org/openhab/binding/dali/internal/protocol/DaliStandardCommand.java @@ -81,7 +81,47 @@ public class DaliStandardCommand extends DaliGearCommandBase { return new DaliStandardCommand(target, 0x90, 0, false); } + public static DaliStandardCommand createQueryContentDTR0Command(DaliAddress target) throws DaliException { + return new DaliStandardCommand(target, 0x98, 0, false); + } + public static DaliStandardCommand createQueryActualLevelCommand(DaliAddress target) throws DaliException { return new DaliStandardCommand(target, 0xa0, 0, false); } + + public static DaliStandardCommand createActivateCommand(DaliAddress target) throws DaliException { + return new DaliStandardCommand(target, 0xe2, 0, false); + } + + public static DaliStandardCommand createQueryColorValueCommand(DaliAddress target) throws DaliException { + return new DaliStandardCommand(target, 0xfa, 0, false); + } + + // Global commands sent to special addresses + + public static DaliStandardCommand createSetDTR0Command(int value) throws DaliException { + return new DaliStandardCommand(DaliAddress.createRawAddress(0xa3), value, 0, false); + } + + public static DaliStandardCommand createSetDTR1Command(int value) throws DaliException { + return new DaliStandardCommand(DaliAddress.createRawAddress(0xc3), value, 0, false); + } + + public static DaliStandardCommand createSetDTR2Command(int value) throws DaliException { + return new DaliStandardCommand(DaliAddress.createRawAddress(0xc5), value, 0, false); + } + + public static DaliStandardCommand createSetDeviceTypeCommand(int value) throws DaliException { + return new DaliStandardCommand(DaliAddress.createRawAddress(0xc1), value, 0, false); + } + + // DT8 (color temperature and single-channel RGB) commands + + public static DaliStandardCommand createSetRgbDimlevelCommand(DaliAddress target) throws DaliException { + return new DaliStandardCommand(target, 0xeb, 0, false); + } + + public static DaliStandardCommand createSetColorTemperatureCommand(DaliAddress target) throws DaliException { + return new DaliStandardCommand(target, 0xe7, 0, false); + } } diff --git a/bundles/org.openhab.binding.dali/src/main/resources/OH-INF/i18n/dali.properties b/bundles/org.openhab.binding.dali/src/main/resources/OH-INF/i18n/dali.properties index 333b4dbd0bd..99ce34dbcd1 100644 --- a/bundles/org.openhab.binding.dali/src/main/resources/OH-INF/i18n/dali.properties +++ b/bundles/org.openhab.binding.dali/src/main/resources/OH-INF/i18n/dali.properties @@ -13,6 +13,10 @@ thing-type.dali.group.label = DALI Group thing-type.dali.group.description = Controls a group of devices/ballasts thing-type.dali.rgb.label = DALI RGB Device thing-type.dali.rgb.description = Controls three DALI devices representing R,G,B lighting channels +thing-type.dali.device-dt8.label = DALI DT8 Device +thing-type.dali.device-dt8.description = Controls a single DT8 device/ballast +thing-type.dali.group-dt8.label = DALI DT8 Group +thing-type.dali.group-dt8.description = Controls a group of DT8 device/ballast # thing types config @@ -24,6 +28,8 @@ thing-type.config.dali.device.targetId.label = Device ID thing-type.config.dali.device.targetId.description = Address of the device in the DALI bus thing-type.config.dali.group.targetId.label = Group ID thing-type.config.dali.group.targetId.description = Address of the group in the DALI bus +thing-type.config.dali.group.readDeviceTargetId.label = Read Device ID +thing-type.config.dali.group.readDeviceTargetId.description = If reading values from this group fails, you can choose to read from a single device instead. thing-type.config.dali.rgb.targetIdB.label = B Device ID thing-type.config.dali.rgb.targetIdB.description = Address of the device in the DALI bus thing-type.config.dali.rgb.targetIdG.label = G Device ID diff --git a/bundles/org.openhab.binding.dali/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.dali/src/main/resources/OH-INF/thing/thing-types.xml index 14da66f0f00..1c13dbdfc50 100644 --- a/bundles/org.openhab.binding.dali/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.dali/src/main/resources/OH-INF/thing/thing-types.xml @@ -48,6 +48,12 @@ Address of the group in the DALI bus + + + + If reading values from this group fails, you can choose to read from a single device instead. + + @@ -78,4 +84,53 @@ + + + + + + + Controls a single DT8 device/ballast + + + + + + + + + + + Address of the device in the DALI bus + + + + + + + + + + + Controls a DT8 group of devices/ballasts + + + + + + + + + + Address of the group in the DALI bus + + + + + If reading values from this group fails, you can choose to read from a single device instead. + + + + +