mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[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 <github-ebqurd@s3lph.me>
This commit is contained in:
parent
3fe5f3f267
commit
4e2d87da5c
@ -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 ]
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -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<ThingTypeUID> 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<ThingTypeUID> 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";
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
@ -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) {
|
||||
|
@ -36,10 +36,27 @@ public abstract class DaliAddress {
|
||||
protected <T extends DaliFrame> 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 extends DaliFrame> 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");
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -48,6 +48,12 @@
|
||||
<label>Group ID</label>
|
||||
<description>Address of the group in the DALI bus</description>
|
||||
</parameter>
|
||||
<parameter name="readDeviceTargetId" type="integer" required="false" min="0" max="63">
|
||||
<label>Read Device ID</label>
|
||||
<description>
|
||||
If reading values from this group fails, you can choose to read from a single device instead.
|
||||
</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
@ -78,4 +84,53 @@
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<!-- Single DT8 Device Type -->
|
||||
<thing-type id="device-dt8">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="daliserver"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>DALI DT8 Device</label>
|
||||
<description>Controls a single DT8 device/ballast</description>
|
||||
<channels>
|
||||
<channel id="dimAtFadeRate" typeId="system.brightness"/>
|
||||
<channel id="dimImmediately" typeId="system.brightness"/>
|
||||
<channel id="color" typeId="system.color"/>
|
||||
<channel id="color-temperature-abs" typeId="system.color-temperature-abs"/>
|
||||
</channels>
|
||||
|
||||
<config-description>
|
||||
<parameter name="targetId" type="integer" required="true" min="0" max="63">
|
||||
<label>Device ID</label>
|
||||
<description>Address of the device in the DALI bus</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<!-- Group DT8 Device Type -->
|
||||
<thing-type id="group-dt8">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="daliserver"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>DALI DT8 Group</label>
|
||||
<description>Controls a DT8 group of devices/ballasts</description>
|
||||
<channels>
|
||||
<channel id="dimAtFadeRate" typeId="system.brightness"/>
|
||||
<channel id="dimImmediately" typeId="system.brightness"/>
|
||||
<channel id="color" typeId="system.color"/>
|
||||
<channel id="color-temperature-abs" typeId="system.color-temperature-abs"/>
|
||||
</channels>
|
||||
<config-description>
|
||||
<parameter name="targetId" type="integer" required="true" min="0" max="31">
|
||||
<label>Group ID</label>
|
||||
<description>Address of the group in the DALI bus</description>
|
||||
</parameter>
|
||||
<parameter name="readDeviceTargetId" type="integer" required="false" min="0" max="63">
|
||||
<label>Read Device ID</label>
|
||||
<description>
|
||||
If reading values from this group fails, you can choose to read from a single device instead.
|
||||
</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
|
Loading…
Reference in New Issue
Block a user