Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[deconz] Added support for publishing ChannelDescriptionChangedEvents #10900

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* 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));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,19 @@

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;
Expand All @@ -34,24 +38,30 @@
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
@Component(service = { DynamicStateDescriptionProvider.class, StateDescriptionProvider.class })
public class StateDescriptionProvider implements DynamicStateDescriptionProvider {
@Component(service = { DynamicStateDescriptionProvider.class, DeconzDynamicStateDescriptionProvider.class })
public class DeconzDynamicStateDescriptionProvider extends BaseDynamicStateDescriptionProvider {
private final Logger logger = LoggerFactory.getLogger(DeconzDynamicStateDescriptionProvider.class);

private final Map<ChannelUID, StateDescription> descriptions = new ConcurrentHashMap<>();
private final Logger logger = LoggerFactory.getLogger(StateDescriptionProvider.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 description
* @param stateDescriptionFragment
* state description for the channel
*/
public void setDescription(ChannelUID channelUID, StateDescription description) {
logger.trace("adding state description for channel {}", channelUID);
descriptions.put(channelUID, description);
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));
}
}

/**
Expand All @@ -61,17 +71,18 @@ public void setDescription(ChannelUID channelUID, StateDescription description)
*/
public void removeDescriptionsForThing(ThingUID thingUID) {
logger.trace("removing state description for thing {}", thingUID);
descriptions.entrySet().removeIf(entry -> entry.getKey().getThingUID().equals(thingUID));
stateDescriptionFragments.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())) {
StateDescriptionFragment stateDescriptionFragment = stateDescriptionFragments.get(channel.getUID());
if (stateDescriptionFragment != null) {
logger.trace("returning new stateDescription for {}", channel.getUID());
return descriptions.get(channel.getUID());
return stateDescriptionFragment.toStateDescription();
} else {
return null;
return super.getStateDescription(channel, originalStateDescription, locale);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,14 @@ public class DeconzHandlerFactory extends BaseThingHandlerFactory {
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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
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.
Expand All @@ -24,4 +25,13 @@
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 + '\'' + '}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@
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;
Expand All @@ -36,8 +37,6 @@
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;
Expand All @@ -56,12 +55,13 @@
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;
}
Expand Down Expand Up @@ -142,10 +142,8 @@ protected void processStateResponse(DeconzBaseMessage stateResponse) {
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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@

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;
Expand All @@ -49,10 +49,9 @@
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;
Expand Down Expand Up @@ -85,8 +84,8 @@ public class LightThingHandler extends DeconzBaseThingHandler {

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;
Expand All @@ -104,8 +103,8 @@ public class LightThingHandler extends DeconzBaseThingHandler {
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;
Expand All @@ -123,15 +122,11 @@ public void initialize() {
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;
}
Expand Down Expand Up @@ -370,20 +365,16 @@ private void checkAndUpdateEffectChannels(LightMessage lightMessage) {
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));
}
}

Expand Down
Loading