+++ /dev/null
-/**
- * Copyright (c) 2010-2021 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.deconz.internal;
-
-import java.util.Locale;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.eclipse.jdt.annotation.Nullable;
-import org.openhab.core.thing.Channel;
-import org.openhab.core.thing.ChannelUID;
-import org.openhab.core.thing.ThingUID;
-import org.openhab.core.thing.type.DynamicCommandDescriptionProvider;
-import org.openhab.core.types.CommandDescription;
-import org.osgi.service.component.annotations.Component;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Dynamic channel command description provider.
- * Overrides the command description for the controls, which receive its configuration in the runtime.
- *
- * @author Jan N. Klug - Initial contribution
- */
-@NonNullByDefault
-@Component(service = { DynamicCommandDescriptionProvider.class, CommandDescriptionProvider.class })
-public class CommandDescriptionProvider implements DynamicCommandDescriptionProvider {
-
- private final Map<ChannelUID, CommandDescription> descriptions = new ConcurrentHashMap<>();
- private final Logger logger = LoggerFactory.getLogger(CommandDescriptionProvider.class);
-
- /**
- * Set a command description for a channel. This description will be used when preparing the channel command by
- * the framework for presentation. A previous description, if existed, will be replaced.
- *
- * @param channelUID
- * channel UID
- * @param description
- * state description for the channel
- */
- public void setDescription(ChannelUID channelUID, CommandDescription description) {
- logger.trace("adding command description for channel {}", channelUID);
- descriptions.put(channelUID, description);
- }
-
- /**
- * remove all descriptions for a given thing
- *
- * @param thingUID the thing's UID
- */
- public void removeDescriptionsForThing(ThingUID thingUID) {
- logger.trace("removing state description for thing {}", thingUID);
- descriptions.entrySet().removeIf(entry -> entry.getKey().getThingUID().equals(thingUID));
- }
-
- @Override
- public @Nullable CommandDescription getCommandDescription(Channel channel,
- @Nullable CommandDescription originalStateDescription, @Nullable Locale locale) {
- if (descriptions.containsKey(channel.getUID())) {
- logger.trace("returning new stateDescription for {}", channel.getUID());
- return descriptions.get(channel.getUID());
- } else {
- return null;
- }
- }
-}
--- /dev/null
+/**
+ * Copyright (c) 2010-2021 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.deconz.internal;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.core.thing.ThingUID;
+import org.openhab.core.thing.binding.BaseDynamicCommandDescriptionProvider;
+import org.openhab.core.thing.type.DynamicCommandDescriptionProvider;
+import org.osgi.service.component.annotations.Component;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Dynamic channel command description provider.
+ * Overrides the command description for the controls, which receive its configuration in the runtime.
+ *
+ * @author Jan N. Klug - Initial contribution
+ */
+@NonNullByDefault
+@Component(service = { DynamicCommandDescriptionProvider.class, DeconzDynamicCommandDescriptionProvider.class })
+public class DeconzDynamicCommandDescriptionProvider extends BaseDynamicCommandDescriptionProvider {
+ private final Logger logger = LoggerFactory.getLogger(DeconzDynamicCommandDescriptionProvider.class);
+
+ /**
+ * remove all descriptions for a given thing
+ *
+ * @param thingUID the thing's UID
+ */
+ public void removeDescriptionsForThing(ThingUID thingUID) {
+ logger.trace("removing state description for thing {}", thingUID);
+ channelOptionsMap.entrySet().removeIf(entry -> entry.getKey().getThingUID().equals(thingUID));
+ }
+}
--- /dev/null
+/**
+ * Copyright (c) 2010-2021 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.deconz.internal;
+
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.core.thing.Channel;
+import org.openhab.core.thing.ChannelUID;
+import org.openhab.core.thing.ThingUID;
+import org.openhab.core.thing.binding.BaseDynamicStateDescriptionProvider;
+import org.openhab.core.thing.events.ThingEventFactory;
+import org.openhab.core.thing.type.DynamicStateDescriptionProvider;
+import org.openhab.core.types.StateDescription;
+import org.openhab.core.types.StateDescriptionFragment;
+import org.osgi.service.component.annotations.Component;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Dynamic channel state description provider.
+ * Overrides the state description for the controls, which receive its configuration in the runtime.
+ *
+ * @author Jan N. Klug - Initial contribution
+ */
+@NonNullByDefault
+@Component(service = { DynamicStateDescriptionProvider.class, DeconzDynamicStateDescriptionProvider.class })
+public class DeconzDynamicStateDescriptionProvider extends BaseDynamicStateDescriptionProvider {
+ private final Logger logger = LoggerFactory.getLogger(DeconzDynamicStateDescriptionProvider.class);
+
+ private final Map<ChannelUID, StateDescriptionFragment> stateDescriptionFragments = new ConcurrentHashMap<>();
+
+ /**
+ * Set a state description for a channel. This description will be used when preparing the channel state by
+ * the framework for presentation. A previous description, if existed, will be replaced.
+ *
+ * @param channelUID
+ * channel UID
+ * @param stateDescriptionFragment
+ * state description for the channel
+ */
+ public void setDescriptionFragment(ChannelUID channelUID, StateDescriptionFragment stateDescriptionFragment) {
+ StateDescriptionFragment oldStateDescriptionFragment = stateDescriptionFragments.get(channelUID);
+ if (!stateDescriptionFragment.equals(oldStateDescriptionFragment)) {
+ logger.trace("adding state description for channel {}", channelUID);
+ stateDescriptionFragments.put(channelUID, stateDescriptionFragment);
+ postEvent(ThingEventFactory.createChannelDescriptionChangedEvent(channelUID,
+ itemChannelLinkRegistry != null ? itemChannelLinkRegistry.getLinkedItemNames(channelUID) : Set.of(),
+ stateDescriptionFragment, oldStateDescriptionFragment));
+ }
+ }
+
+ /**
+ * remove all descriptions for a given thing
+ *
+ * @param thingUID the thing's UID
+ */
+ public void removeDescriptionsForThing(ThingUID thingUID) {
+ logger.trace("removing state description for thing {}", thingUID);
+ stateDescriptionFragments.entrySet().removeIf(entry -> entry.getKey().getThingUID().equals(thingUID));
+ }
+
+ @Override
+ public @Nullable StateDescription getStateDescription(Channel channel,
+ @Nullable StateDescription originalStateDescription, @Nullable Locale locale) {
+ StateDescriptionFragment stateDescriptionFragment = stateDescriptionFragments.get(channel.getUID());
+ if (stateDescriptionFragment != null) {
+ logger.trace("returning new stateDescription for {}", channel.getUID());
+ return stateDescriptionFragment.toStateDescription();
+ } else {
+ return super.getStateDescription(channel, originalStateDescription, locale);
+ }
+ }
+}
private final Gson gson;
private final WebSocketFactory webSocketFactory;
private final HttpClientFactory httpClientFactory;
- private final StateDescriptionProvider stateDescriptionProvider;
- private final CommandDescriptionProvider commandDescriptionProvider;
+ private final DeconzDynamicStateDescriptionProvider stateDescriptionProvider;
+ private final DeconzDynamicCommandDescriptionProvider commandDescriptionProvider;
@Activate
public DeconzHandlerFactory(final @Reference WebSocketFactory webSocketFactory,
final @Reference HttpClientFactory httpClientFactory,
- final @Reference StateDescriptionProvider stateDescriptionProvider,
- final @Reference CommandDescriptionProvider commandDescriptionProvider) {
+ final @Reference DeconzDynamicStateDescriptionProvider stateDescriptionProvider,
+ final @Reference DeconzDynamicCommandDescriptionProvider commandDescriptionProvider) {
this.webSocketFactory = webSocketFactory;
this.httpClientFactory = httpClientFactory;
this.stateDescriptionProvider = stateDescriptionProvider;
+++ /dev/null
-/**
- * Copyright (c) 2010-2021 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.deconz.internal;
-
-import java.util.Locale;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.eclipse.jdt.annotation.Nullable;
-import org.openhab.core.thing.Channel;
-import org.openhab.core.thing.ChannelUID;
-import org.openhab.core.thing.ThingUID;
-import org.openhab.core.thing.type.DynamicStateDescriptionProvider;
-import org.openhab.core.types.StateDescription;
-import org.osgi.service.component.annotations.Component;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Dynamic channel state description provider.
- * Overrides the state description for the controls, which receive its configuration in the runtime.
- *
- * @author Jan N. Klug - Initial contribution
- */
-@NonNullByDefault
-@Component(service = { DynamicStateDescriptionProvider.class, StateDescriptionProvider.class })
-public class StateDescriptionProvider implements DynamicStateDescriptionProvider {
-
- private final Map<ChannelUID, StateDescription> descriptions = new ConcurrentHashMap<>();
- private final Logger logger = LoggerFactory.getLogger(StateDescriptionProvider.class);
-
- /**
- * Set a state description for a channel. This description will be used when preparing the channel state by
- * the framework for presentation. A previous description, if existed, will be replaced.
- *
- * @param channelUID
- * channel UID
- * @param description
- * state description for the channel
- */
- public void setDescription(ChannelUID channelUID, StateDescription description) {
- logger.trace("adding state description for channel {}", channelUID);
- descriptions.put(channelUID, description);
- }
-
- /**
- * remove all descriptions for a given thing
- *
- * @param thingUID the thing's UID
- */
- public void removeDescriptionsForThing(ThingUID thingUID) {
- logger.trace("removing state description for thing {}", thingUID);
- descriptions.entrySet().removeIf(entry -> entry.getKey().getThingUID().equals(thingUID));
- }
-
- @Override
- public @Nullable StateDescription getStateDescription(Channel channel,
- @Nullable StateDescription originalStateDescription, @Nullable Locale locale) {
- if (descriptions.containsKey(channel.getUID())) {
- logger.trace("returning new stateDescription for {}", channel.getUID());
- return descriptions.get(channel.getUID());
- } else {
- return null;
- }
- }
-}
package org.openhab.binding.deconz.internal.dto;
import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.core.types.CommandOption;
/**
* The {@link Scene} is send by the websocket connection as well as the Rest API.
public class Scene {
public String id = "";
public String name = "";
+
+ public CommandOption toCommandOption() {
+ return new CommandOption(name, name);
+ }
+
+ @Override
+ public String toString() {
+ return "Scene{" + "id='" + id + '\'' + ", name='" + name + '\'' + '}';
+ }
}
import java.util.stream.Collectors;
import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.openhab.binding.deconz.internal.CommandDescriptionProvider;
+import org.openhab.binding.deconz.internal.DeconzDynamicCommandDescriptionProvider;
import org.openhab.binding.deconz.internal.Util;
import org.openhab.binding.deconz.internal.dto.DeconzBaseMessage;
import org.openhab.binding.deconz.internal.dto.GroupAction;
import org.openhab.binding.deconz.internal.dto.GroupMessage;
import org.openhab.binding.deconz.internal.dto.GroupState;
+import org.openhab.binding.deconz.internal.dto.Scene;
import org.openhab.binding.deconz.internal.types.ResourceType;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.HSBType;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.types.Command;
-import org.openhab.core.types.CommandDescriptionBuilder;
-import org.openhab.core.types.CommandOption;
import org.openhab.core.types.RefreshType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class GroupThingHandler extends DeconzBaseThingHandler {
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPE_UIDS = Set.of(THING_TYPE_LIGHTGROUP);
private final Logger logger = LoggerFactory.getLogger(GroupThingHandler.class);
- private final CommandDescriptionProvider commandDescriptionProvider;
+ private final DeconzDynamicCommandDescriptionProvider commandDescriptionProvider;
private Map<String, String> scenes = Map.of();
private GroupState groupStateCache = new GroupState();
- public GroupThingHandler(Thing thing, Gson gson, CommandDescriptionProvider commandDescriptionProvider) {
+ public GroupThingHandler(Thing thing, Gson gson,
+ DeconzDynamicCommandDescriptionProvider commandDescriptionProvider) {
super(thing, gson, ResourceType.GROUPS);
this.commandDescriptionProvider = commandDescriptionProvider;
}
GroupMessage groupMessage = (GroupMessage) stateResponse;
scenes = groupMessage.scenes.stream().collect(Collectors.toMap(scene -> scene.name, scene -> scene.id));
ChannelUID channelUID = new ChannelUID(thing.getUID(), CHANNEL_SCENE);
- commandDescriptionProvider.setDescription(channelUID,
- CommandDescriptionBuilder.create().withCommandOptions(groupMessage.scenes.stream()
- .map(scene -> new CommandOption(scene.name, scene.name)).collect(Collectors.toList()))
- .build());
+ commandDescriptionProvider.setCommandOptions(channelUID,
+ groupMessage.scenes.stream().map(Scene::toCommandOption).collect(Collectors.toList()));
}
messageReceived(config.id, stateResponse);
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
-import org.openhab.binding.deconz.internal.CommandDescriptionProvider;
-import org.openhab.binding.deconz.internal.StateDescriptionProvider;
+import org.openhab.binding.deconz.internal.DeconzDynamicCommandDescriptionProvider;
+import org.openhab.binding.deconz.internal.DeconzDynamicStateDescriptionProvider;
import org.openhab.binding.deconz.internal.Util;
import org.openhab.binding.deconz.internal.dto.DeconzBaseMessage;
import org.openhab.binding.deconz.internal.dto.LightMessage;
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.CommandDescriptionBuilder;
import org.openhab.core.types.CommandOption;
import org.openhab.core.types.RefreshType;
-import org.openhab.core.types.StateDescription;
+import org.openhab.core.types.StateDescriptionFragment;
import org.openhab.core.types.StateDescriptionFragmentBuilder;
import org.openhab.core.types.UnDefType;
import org.slf4j.Logger;
private final Logger logger = LoggerFactory.getLogger(LightThingHandler.class);
- private final StateDescriptionProvider stateDescriptionProvider;
- private final CommandDescriptionProvider commandDescriptionProvider;
+ private final DeconzDynamicStateDescriptionProvider stateDescriptionProvider;
+ private final DeconzDynamicCommandDescriptionProvider commandDescriptionProvider;
private long lastCommandExpireTimestamp = 0;
private boolean needsPropertyUpdate = false;
private int ctMax = ZCL_CT_MAX;
private int ctMin = ZCL_CT_MIN;
- public LightThingHandler(Thing thing, Gson gson, StateDescriptionProvider stateDescriptionProvider,
- CommandDescriptionProvider commandDescriptionProvider) {
+ public LightThingHandler(Thing thing, Gson gson, DeconzDynamicStateDescriptionProvider stateDescriptionProvider,
+ DeconzDynamicCommandDescriptionProvider commandDescriptionProvider) {
super(thing, gson, ResourceType.LIGHTS);
this.stateDescriptionProvider = stateDescriptionProvider;
this.commandDescriptionProvider = commandDescriptionProvider;
ctMin = ctMinString == null ? ZCL_CT_MIN : Integer.parseInt(ctMinString);
// minimum and maximum are inverted due to mired/kelvin conversion!
- StateDescription stateDescription = StateDescriptionFragmentBuilder.create()
+ StateDescriptionFragment stateDescriptionFragment = StateDescriptionFragmentBuilder.create()
.withMinimum(new BigDecimal(miredToKelvin(ctMax)))
- .withMaximum(new BigDecimal(miredToKelvin(ctMin))).build().toStateDescription();
- if (stateDescription != null) {
- stateDescriptionProvider.setDescription(new ChannelUID(thing.getUID(), CHANNEL_COLOR_TEMPERATURE),
- stateDescription);
- } else {
- logger.warn("Failed to create state description in thing {}", thing.getUID());
- }
+ .withMaximum(new BigDecimal(miredToKelvin(ctMin))).build();
+ stateDescriptionProvider.setDescriptionFragment(
+ new ChannelUID(thing.getUID(), CHANNEL_COLOR_TEMPERATURE), stateDescriptionFragment);
} catch (NumberFormatException e) {
needsPropertyUpdate = true;
}
List<String> options = List.of("none", "steady", "snow", "rainbow", "snake", "tinkle", "fireworks",
"flag", "waves", "updown", "vintage", "fading", "collide", "strobe", "sparkles", "carnival",
"glow");
- commandDescriptionProvider.setDescription(effectChannelUID,
- CommandDescriptionBuilder.create().withCommandOptions(toCommandOptionList(options)).build());
+ commandDescriptionProvider.setCommandOptions(effectChannelUID, toCommandOptionList(options));
break;
case TINT_MUELLER:
options = List.of("none", "colorloop", "sunset", "party", "worklight", "campfire", "romance",
"nightlight");
- commandDescriptionProvider.setDescription(effectChannelUID,
- CommandDescriptionBuilder.create().withCommandOptions(toCommandOptionList(options)).build());
+ commandDescriptionProvider.setCommandOptions(effectChannelUID, toCommandOptionList(options));
break;
default:
options = List.of("none", "colorloop");
- commandDescriptionProvider.setDescription(effectChannelUID,
- CommandDescriptionBuilder.create().withCommandOptions(toCommandOptionList(options)).build());
-
+ commandDescriptionProvider.setCommandOptions(effectChannelUID, toCommandOptionList(options));
}
}
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
-import org.openhab.binding.deconz.internal.CommandDescriptionProvider;
-import org.openhab.binding.deconz.internal.StateDescriptionProvider;
+import org.openhab.binding.deconz.internal.DeconzDynamicCommandDescriptionProvider;
+import org.openhab.binding.deconz.internal.DeconzDynamicStateDescriptionProvider;
import org.openhab.binding.deconz.internal.dto.LightMessage;
import org.openhab.binding.deconz.internal.handler.LightThingHandler;
import org.openhab.binding.deconz.internal.types.LightType;
private @NonNullByDefault({}) Gson gson;
private @Mock @NonNullByDefault({}) ThingHandlerCallback thingHandlerCallback;
- private @Mock @NonNullByDefault({}) StateDescriptionProvider stateDescriptionProvider;
- private @Mock @NonNullByDefault({}) CommandDescriptionProvider commandDescriptionProvider;
+ private @Mock @NonNullByDefault({}) DeconzDynamicStateDescriptionProvider stateDescriptionProvider;
+ private @Mock @NonNullByDefault({}) DeconzDynamicCommandDescriptionProvider commandDescriptionProvider;
@BeforeEach
public void initialize() {
lightThingHandler.initialize();
- Mockito.verify(stateDescriptionProvider).setDescription(eq(channelUID_ct), any());
+ Mockito.verify(stateDescriptionProvider).setDescriptionFragment(eq(channelUID_ct), any());
}
@Test