import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
+import javax.measure.Unit;
+
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.knx.internal.KNXBindingConstants;
import org.openhab.binding.knx.internal.client.KNXClient;
import org.openhab.binding.knx.internal.client.OutboundSpec;
import org.openhab.binding.knx.internal.config.DeviceConfig;
+import org.openhab.binding.knx.internal.dpt.DPTUnits;
import org.openhab.binding.knx.internal.dpt.DPTUtil;
import org.openhab.binding.knx.internal.dpt.ValueDecoder;
import org.openhab.binding.knx.internal.i18n.KNXTranslationProvider;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.ThingStatusInfo;
import org.openhab.core.thing.binding.BaseThingHandler;
+import org.openhab.core.thing.binding.ThingHandlerCallback;
+import org.openhab.core.thing.binding.builder.ChannelBuilder;
+import org.openhab.core.thing.binding.builder.ThingBuilder;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.openhab.core.types.State;
import org.openhab.core.types.Type;
import org.openhab.core.types.UnDefType;
+import org.openhab.core.types.util.UnitUtils;
import org.openhab.core.util.HexUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Override
public void initialize() {
- attachToClient();
DeviceConfig config = getConfigAs(DeviceConfig.class);
readInterval = config.getReadInterval();
+
// gather all GAs from channel configurations and create channels
- getThing().getChannels().forEach(channel -> {
+ ThingBuilder thingBuilder = editThing();
+ boolean modified = false;
+ ThingHandlerCallback callback = getCallback();
+ if (callback == null) {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "Framework failure: callback must not be null");
+ return;
+ }
+
+ for (Channel channel : getThing().getChannels()) {
KNXChannel knxChannel = KNXChannelFactory.createKnxChannel(channel);
knxChannels.put(channel.getUID(), knxChannel);
groupAddresses.addAll(knxChannel.getAllGroupAddresses());
- });
+
+ if (knxChannel.getChannelType().startsWith("number")) {
+ // check if we need to update the accepted item-type
+ List<InboundSpec> inboundSpecs = knxChannel.getAllGroupAddresses().stream()
+ .map(knxChannel::getListenSpec).filter(Objects::nonNull).map(Objects::requireNonNull).toList();
+
+ String dpt = inboundSpecs.get(0).getDPT(); // there can be only one DPT on number channels
+ Unit<?> unit = UnitUtils.parseUnit(DPTUnits.getUnitForDpt(dpt));
+ String dimension = unit == null ? null : UnitUtils.getDimensionName(unit);
+ String expectedItemType = dimension == null ? "Number" : "Number:" + dimension; // unknown dimension ->
+ // Number
+ String actualItemType = channel.getAcceptedItemType();
+ if (!expectedItemType.equals(actualItemType)) {
+ ChannelBuilder channelBuilder = callback
+ .createChannelBuilder(channel.getUID(), Objects.requireNonNull(channel.getChannelTypeUID()))
+ .withAcceptedItemType(expectedItemType).withConfiguration(channel.getConfiguration());
+ if (channel.getLabel() != null) {
+ channelBuilder.withLabel(Objects.requireNonNull(channel.getLabel()));
+ }
+ if (channel.getDescription() != null) {
+ channelBuilder.withDescription(Objects.requireNonNull(channel.getDescription()));
+ }
+ thingBuilder.withoutChannel(channel.getUID());
+ thingBuilder.withChannel(channelBuilder.build());
+ modified = true;
+ }
+ }
+ }
+
+ if (modified) {
+ updateThing(thingBuilder.build());
+ }
+
+ attachToClient();
}
@Override