diff --git a/bundles/org.openhab.binding.remoteopenhab/src/main/java/org/openhab/binding/remoteopenhab/internal/RemoteopenhabChannelTypeProvider.java b/bundles/org.openhab.binding.remoteopenhab/src/main/java/org/openhab/binding/remoteopenhab/internal/RemoteopenhabChannelTypeProvider.java index 7fe87fe6b4deb..401abb869dad4 100644 --- a/bundles/org.openhab.binding.remoteopenhab/src/main/java/org/openhab/binding/remoteopenhab/internal/RemoteopenhabChannelTypeProvider.java +++ b/bundles/org.openhab.binding.remoteopenhab/src/main/java/org/openhab/binding/remoteopenhab/internal/RemoteopenhabChannelTypeProvider.java @@ -12,9 +12,13 @@ */ package org.openhab.binding.remoteopenhab.internal; +import static org.openhab.binding.remoteopenhab.internal.RemoteopenhabBindingConstants.BINDING_ID; + import java.util.Collection; import java.util.List; import java.util.Locale; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import org.eclipse.jdt.annotation.NonNullByDefault; @@ -22,6 +26,7 @@ import org.openhab.core.thing.type.ChannelType; import org.openhab.core.thing.type.ChannelTypeProvider; import org.openhab.core.thing.type.ChannelTypeUID; +import org.openhab.core.types.StateDescription; import org.osgi.service.component.annotations.Component; /** @@ -34,6 +39,7 @@ @NonNullByDefault public class RemoteopenhabChannelTypeProvider implements ChannelTypeProvider { private final List channelTypes = new CopyOnWriteArrayList<>(); + private final Map> channelTypesForItemTypes = new ConcurrentHashMap<>(); @Override public Collection getChannelTypes(@Nullable Locale locale) { @@ -50,11 +56,48 @@ public Collection getChannelTypes(@Nullable Locale locale) { return null; } - public void addChannelType(ChannelType type) { - channelTypes.add(type); + public @Nullable ChannelType getChannelType(String itemType, boolean readOnly, String pattern) { + List channelTypesForItemType = channelTypesForItemTypes.get(itemType); + if (channelTypesForItemType != null) { + for (ChannelType channelType : channelTypesForItemType) { + boolean channelTypeReadOnly = false; + String channelTypePattern = null; + StateDescription stateDescription = channelType.getState(); + if (stateDescription != null) { + channelTypeReadOnly = stateDescription.isReadOnly(); + channelTypePattern = stateDescription.getPattern(); + } + if (channelTypePattern == null) { + channelTypePattern = ""; + } + if (channelTypeReadOnly == readOnly && channelTypePattern.equals(pattern)) { + return channelType; + } + } + } + return null; + } + + public ChannelTypeUID buildNewChannelTypeUID(String itemType) { + List channelTypesForItemType = channelTypesForItemTypes.get(itemType); + int nb = channelTypesForItemType == null ? 0 : channelTypesForItemType.size(); + return new ChannelTypeUID(BINDING_ID, String.format("item%s%d", itemType.replace(":", ""), nb + 1)); } - public void removeChannelType(ChannelType type) { - channelTypes.remove(type); + public void addChannelType(String itemType, ChannelType channelType) { + channelTypes.add(channelType); + List channelTypesForItemType = channelTypesForItemTypes.computeIfAbsent(itemType, + type -> new CopyOnWriteArrayList<>()); + if (channelTypesForItemType != null) { + channelTypesForItemType.add(channelType); + } + } + + public void removeChannelType(String itemType, ChannelType channelType) { + channelTypes.remove(channelType); + List channelTypesForItemType = channelTypesForItemTypes.get(itemType); + if (channelTypesForItemType != null) { + channelTypesForItemType.remove(channelType); + } } } diff --git a/bundles/org.openhab.binding.remoteopenhab/src/main/java/org/openhab/binding/remoteopenhab/internal/handler/RemoteopenhabBridgeHandler.java b/bundles/org.openhab.binding.remoteopenhab/src/main/java/org/openhab/binding/remoteopenhab/internal/handler/RemoteopenhabBridgeHandler.java index 91273804683b7..e9c93a1fbb3e8 100644 --- a/bundles/org.openhab.binding.remoteopenhab/src/main/java/org/openhab/binding/remoteopenhab/internal/handler/RemoteopenhabBridgeHandler.java +++ b/bundles/org.openhab.binding.remoteopenhab/src/main/java/org/openhab/binding/remoteopenhab/internal/handler/RemoteopenhabBridgeHandler.java @@ -12,8 +12,6 @@ */ package org.openhab.binding.remoteopenhab.internal.handler; -import static org.openhab.binding.remoteopenhab.internal.RemoteopenhabBindingConstants.BINDING_ID; - import java.net.MalformedURLException; import java.net.URL; import java.time.ZonedDateTime; @@ -217,6 +215,7 @@ private boolean createChannels(List items, boolean replace) { synchronized (updateThingLock) { try { int nbGroups = 0; + int nbChannelTypesCreated = 0; List channels = new ArrayList<>(); for (RemoteopenhabItem item : items) { String itemType = item.type; @@ -234,21 +233,33 @@ private boolean createChannels(List items, boolean replace) { readOnly = true; } } - String channelTypeId = String.format("item%s%s", itemType.replace(":", ""), readOnly ? "RO" : ""); - ChannelTypeUID channelTypeUID = new ChannelTypeUID(BINDING_ID, channelTypeId); - ChannelType channelType = channelTypeProvider.getChannelType(channelTypeUID, null); + // Ignore pattern containing a transformation (detected by a parenthesis in the pattern) + RemoteopenhabStateDescription stateDescription = item.stateDescription; + String pattern = (stateDescription == null || stateDescription.pattern.contains("(")) ? "" + : stateDescription.pattern; + ChannelTypeUID channelTypeUID; + ChannelType channelType = channelTypeProvider.getChannelType(itemType, readOnly, pattern); String label; String description; if (channelType == null) { - logger.trace("Create the channel type {} for item type {}", channelTypeUID, itemType); + channelTypeUID = channelTypeProvider.buildNewChannelTypeUID(itemType); + logger.trace("Create the channel type {} for item type {} ({} and with pattern {})", + channelTypeUID, itemType, readOnly ? "read only" : "read write", pattern); label = String.format("Remote %s Item", itemType); description = String.format("An item of type %s from the remote server.", itemType); + StateDescriptionFragmentBuilder stateDescriptionBuilder = StateDescriptionFragmentBuilder + .create().withReadOnly(readOnly); + if (!pattern.isEmpty()) { + stateDescriptionBuilder = stateDescriptionBuilder.withPattern(pattern); + } channelType = ChannelTypeBuilder.state(channelTypeUID, label, itemType) .withDescription(description) - .withStateDescriptionFragment( - StateDescriptionFragmentBuilder.create().withReadOnly(readOnly).build()) + .withStateDescriptionFragment(stateDescriptionBuilder.build()) .withAutoUpdatePolicy(AutoUpdatePolicy.VETO).build(); - channelTypeProvider.addChannelType(channelType); + channelTypeProvider.addChannelType(itemType, channelType); + nbChannelTypesCreated++; + } else { + channelTypeUID = channelType.getUID(); } ChannelUID channelUID = new ChannelUID(getThing().getUID(), item.name); logger.trace("Create the channel {} of type {}", channelUID, channelTypeUID); @@ -261,8 +272,9 @@ private boolean createChannels(List items, boolean replace) { if (replace) { thingBuilder.withChannels(channels); updateThing(thingBuilder.build()); - logger.debug("{} channels defined for the thing {} (from {} items including {} groups)", - channels.size(), getThing().getUID(), items.size(), nbGroups); + logger.debug( + "{} channels defined (with {} different channel types) for the thing {} (from {} items including {} groups)", + channels.size(), nbChannelTypesCreated, getThing().getUID(), items.size(), nbGroups); } else if (channels.size() > 0) { int nbRemoved = 0; for (Channel channel : channels) {