Skip to content

Commit

Permalink
WIP: Extend ChannelType description by command options
Browse files Browse the repository at this point in the history
This is WIP and open for discussion.

This addresses eclipse-archived#5099 by adding command options as an alternative to a state description.
The implementation is naive and straigt forward.
Command options will be rendered as push buttons by UIs and send the corresponding command value as a command to the channel.
With this proposal, the state of the channel will not be represented in the UI, so ThingHandelers may not even update the state.

Signed-off-by: Henning Treu <[email protected]>
  • Loading branch information
Henning Treu committed Nov 6, 2018
1 parent 8fcf2a4 commit 3e03b67
Show file tree
Hide file tree
Showing 15 changed files with 224 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -109,13 +109,13 @@ public void setup() {
final ChannelType channelType2 = new ChannelType(new ChannelTypeUID("hue:num"), false, "Number", " ", "", null,
null, state2, null);
final ChannelType channelType3 = new ChannelType(new ChannelTypeUID("hue:info"), true, "String", " ", "", null,
null, null, null);
null, (StateDescription) null, null);
final ChannelType channelType4 = new ChannelType(new ChannelTypeUID("hue:color"), false, "Color", "Color", "",
"ColorLight", null, null, null);
"ColorLight", null, (StateDescription) null, null);
final ChannelType channelType5 = new ChannelType(new ChannelTypeUID("hue:brightness"), false, "Dimmer",
"Brightness", "", "DimmableLight", null, null, null);
"Brightness", "", "DimmableLight", null, (StateDescription) null, null);
final ChannelType channelType6 = new ChannelType(new ChannelTypeUID("hue:switch"), false, "Switch", "Switch",
"", "Light", null, null, null);
"", "Light", null, (StateDescription) null, null);
final ChannelType channelType7 = new ChannelType(new ChannelTypeUID("hue:num-dynamic"), false, "Number", " ",
"", "Light", null, state, null);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
package org.eclipse.smarthome.core.thing.xml.internal;

import java.net.URI;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
Expand All @@ -28,6 +29,8 @@
import org.eclipse.smarthome.core.thing.type.ChannelType;
import org.eclipse.smarthome.core.thing.type.ChannelTypeBuilder;
import org.eclipse.smarthome.core.thing.type.ChannelTypeUID;
import org.eclipse.smarthome.core.thing.type.StateChannelTypeBuilder;
import org.eclipse.smarthome.core.types.CommandOption;
import org.eclipse.smarthome.core.types.EventDescription;
import org.eclipse.smarthome.core.types.StateDescription;

Expand Down Expand Up @@ -140,6 +143,33 @@ private EventDescription readEventDescription(NodeIterator nodeIterator) {
return null;
}

private List<CommandOption> readCommandOptions(NodeIterator nodeIterator) throws ConversionException {
List<CommandOption> commandOptions = null;

List<?> commandOptionsNode = nodeIterator.nextList("command-options", false);

if (commandOptionsNode != null) {
commandOptions = new ArrayList<>(commandOptionsNode.size());

for (Object coNodeObject : commandOptionsNode) {
NodeValue commandOptionNode = (NodeValue) coNodeObject;

if ("option".equals(commandOptionNode.getNodeName())) {
String name = (String) commandOptionNode.getValue();
String command = commandOptionNode.getAttributes().get("value");

if (name != null && command != null) {
commandOptions.add(new CommandOption(command, name));
}
} else {
throw new ConversionException("The 'command-options' node must only contain 'option' nodes!");
}
}
}

return commandOptions;
}

@Override
protected ChannelTypeXmlResult unmarshalType(HierarchicalStreamReader reader, UnmarshallingContext context,
Map<String, String> attributes, NodeIterator nodeIterator) throws ConversionException {
Expand All @@ -155,6 +185,7 @@ protected ChannelTypeXmlResult unmarshalType(HierarchicalStreamReader reader, Un
String description = super.readDescription(nodeIterator);
String category = readCategory(nodeIterator);
Set<String> tags = readTags(nodeIterator);
List<CommandOption> commandOptions = readCommandOptions(nodeIterator);

StateDescription stateDescription = readStateDescription(nodeIterator);
EventDescription eventDescription = readEventDescription(nodeIterator);
Expand All @@ -172,10 +203,14 @@ protected ChannelTypeXmlResult unmarshalType(HierarchicalStreamReader reader, Un
URI configDescriptionURI = (URI) configDescriptionObjects[0];
ChannelType channelType = null;
if (cKind == ChannelKind.STATE) {
channelType = ChannelTypeBuilder.state(channelTypeUID, label, itemType).isAdvanced(advanced)
.withDescription(description).withCategory(category).withTags(tags)
StateChannelTypeBuilder builder = ChannelTypeBuilder.state(channelTypeUID, label, itemType)
.isAdvanced(advanced).withDescription(description).withCategory(category).withTags(tags)
.withConfigDescriptionURI(configDescriptionURI).withStateDescription(stateDescription)
.withAutoUpdatePolicy(autoUpdatePolicy).build();
.withAutoUpdatePolicy(autoUpdatePolicy);
if (stateDescription == null && commandOptions != null) {
builder.withCommandOptions(commandOptions);
}
channelType = builder.build();
} else if (cKind == ChannelKind.TRIGGER) {
channelType = ChannelTypeBuilder.trigger(channelTypeUID, label).isAdvanced(advanced)
.withDescription(description).withCategory(category).withTags(tags)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ public void registerAliases(XStream xstream) {
xstream.alias("properties", NodeList.class);
xstream.alias("property", NodeValue.class);
xstream.alias("representation-property", NodeValue.class);
xstream.alias("command-options", NodeList.class);
xstream.alias("autoUpdatePolicy", NodeValue.class);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ protected ChannelType localize(Bundle bundle, ChannelType channelType, Locale lo
if (channelTypeI18nLocalizationService == null) {
return null;
}

return channelTypeI18nLocalizationService.createLocalizedChannelType(bundle, channelType, locale);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,10 @@
<xs:element name="description" type="xs:string" minOccurs="0"/>
<xs:element name="category" type="xs:string" minOccurs="0"/>
<xs:element name="tags" type="thing-description:tags" minOccurs="0"/>
<xs:element name="state" type="thing-description:state" minOccurs="0"/>
<xs:choice minOccurs="0">
<xs:element name="state" type="thing-description:state"/>
<xs:element name="command-options" type="thing-description:command-options"/>
</xs:choice>
<xs:element name="event" type="thing-description:event" minOccurs="0"/>
<xs:element name="autoUpdatePolicy" type="thing-description:auto-update-policy" minOccurs="0"/>
<xs:choice minOccurs="0">
Expand Down Expand Up @@ -170,6 +173,12 @@
</xs:sequence>
</xs:complexType>

<xs:complexType name="command-options">
<xs:sequence>
<xs:element name="option" type="thing-description:option" minOccurs="1" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>

<xs:complexType name="option">
<xs:simpleContent>
<xs:extension base="xs:string">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@

import java.util.List;
import java.util.Set;

import org.eclipse.smarthome.config.core.dto.ConfigDescriptionParameterDTO;
import org.eclipse.smarthome.config.core.dto.ConfigDescriptionParameterGroupDTO;
import org.eclipse.smarthome.core.thing.type.ChannelKind;
import org.eclipse.smarthome.core.types.CommandOption;
import org.eclipse.smarthome.core.types.StateDescription;

/**
Expand All @@ -38,14 +40,15 @@ public class ChannelTypeDTO {
public Set<String> tags;
public String UID;
public boolean advanced;
public List<CommandOption> commandOptions;

public ChannelTypeDTO() {
}

public ChannelTypeDTO(String UID, String label, String description, String category, String itemType,
ChannelKind kind, List<ConfigDescriptionParameterDTO> parameters,
List<ConfigDescriptionParameterGroupDTO> parameterGroups, StateDescription stateDescription,
Set<String> tags, boolean advanced) {
Set<String> tags, boolean advanced, List<CommandOption> commandOptions) {
this.UID = UID;
this.label = label;
this.description = description;
Expand All @@ -57,5 +60,6 @@ public ChannelTypeDTO(String UID, String label, String description, String categ
this.kind = kind.toString();
this.itemType = itemType;
this.advanced = advanced;
this.commandOptions = commandOptions;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ public ChannelType createLocalizedChannelType(Bundle bundle, ChannelType channel
if (description != null) {
stateBuilder.withDescription(description);
}
if (state == null && channelType.getCommandOptions() != null) {
stateBuilder.withCommandOptions(channelType.getCommandOptions());
}
return stateBuilder.build();
case TRIGGER:
TriggerChannelTypeBuilder triggerBuilder = ChannelTypeBuilder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
*/
package org.eclipse.smarthome.core.thing.internal.type;

import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
Expand All @@ -20,6 +22,7 @@
import org.eclipse.smarthome.core.thing.type.ChannelType;
import org.eclipse.smarthome.core.thing.type.ChannelTypeUID;
import org.eclipse.smarthome.core.thing.type.StateChannelTypeBuilder;
import org.eclipse.smarthome.core.types.CommandOption;
import org.eclipse.smarthome.core.types.StateDescription;

/**
Expand All @@ -35,6 +38,7 @@ public class StateChannelTypeBuilderImpl extends AbstractChannelTypeBuilder<Stat
private final String itemType;
private @Nullable StateDescription stateDescription;
private @Nullable AutoUpdatePolicy autoUpdatePolicy;
private @Nullable List<CommandOption> commandOptions;

public StateChannelTypeBuilderImpl(ChannelTypeUID channelTypeUID, String label, String itemType) {
super(channelTypeUID, label);
Expand All @@ -58,10 +62,21 @@ public StateChannelTypeBuilder withAutoUpdatePolicy(@Nullable AutoUpdatePolicy a
return this;
}

@Override
public StateChannelTypeBuilder withCommandOptions(List<CommandOption> commandOptions) {
this.commandOptions = commandOptions;
return this;
}

@Override
public ChannelType build() {
return new ChannelType(channelTypeUID, advanced, itemType, ChannelKind.STATE, label, description, category,
tags.isEmpty() ? null : tags, stateDescription, null, configDescriptionURI, autoUpdatePolicy);
if (stateDescription != null) {
return new ChannelType(channelTypeUID, advanced, itemType, ChannelKind.STATE, label, description, category,
tags.isEmpty() ? null : tags, stateDescription, null, configDescriptionURI, autoUpdatePolicy);
}

return new ChannelType(channelTypeUID, advanced, itemType, label, description, category,
tags.isEmpty() ? null : tags, commandOptions, configDescriptionURI, autoUpdatePolicy);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@
import java.net.URI;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.eclipse.smarthome.config.core.ConfigDescription;
import org.eclipse.smarthome.core.thing.Channel;
import org.eclipse.smarthome.core.types.CommandOption;
import org.eclipse.smarthome.core.types.EventDescription;
import org.eclipse.smarthome.core.types.StateDescription;

Expand All @@ -31,6 +33,7 @@
* <b>Hint:</b> This class is immutable.
*
* @author Michael Grammling - Initial Contribution
* @author Henning Treu - add command options
*/
public class ChannelType extends AbstractDescriptionType {

Expand All @@ -40,6 +43,7 @@ public class ChannelType extends AbstractDescriptionType {
private final Set<String> tags;
private final String category;
private final StateDescription state;
private final List<CommandOption> commandOptions;
private final EventDescription event;
private final URI configDescriptionURI;
private final AutoUpdatePolicy autoUpdatePolicy;
Expand All @@ -65,6 +69,35 @@ public ChannelType(ChannelTypeUID uid, boolean advanced, String itemType, Channe
null);
}

/**
* Creates a new instance of a "write-only" {@link ChannelType} with command options. The purpose of this
* {@link ChannelType} is to send command to a device without updating the state of the corresponding channel.
* E.g. activate a special device mode which is not represented as a definitive state.
*
* @param uid the unique identifier which identifies this Channel type within
* the overall system (must neither be null, nor empty)
* @param advanced true if this channel type contains advanced features, otherwise false
* @param itemType the item type of this Channel type, e.g. {@code ColorItem} (must neither be null nor empty)
* @param label the human readable label for the according type
* (must neither be null nor empty)
* @param description the human readable description for the according type
* (could be null or empty)
* @param category the category of this Channel type, e.g. {@code TEMPERATURE} (could be null or empty)
* @param tags all tags of this {@link ChannelType}, e.g. {@code Alarm} (could be null or empty)
* @param commandOptions a list of {@link CommandOption}s which should be rendered as push-buttons. The command
* values will be send to the channel from this {@link ChannelType}.
* @param configDescriptionURI the link to the concrete ConfigDescription (could be null)
* @param autoUpdatePolicy the {@link AutoUpdatePolicy} to use.
* @throws IllegalArgumentException if the UID or the item type is null or empty,
* or the meta information is null
*/
public ChannelType(ChannelTypeUID uid, boolean advanced, String itemType, String label, String description,
String category, Set<String> tags, List<CommandOption> commandOptions, URI configDescriptionURI,
AutoUpdatePolicy autoUpdatePolicy) {
this(uid, advanced, itemType, ChannelKind.STATE, label, description, category, tags, null, commandOptions, null,
configDescriptionURI, autoUpdatePolicy);
}

/**
* Creates a new instance of this class with the specified parameters.
*
Expand All @@ -84,11 +117,19 @@ public ChannelType(ChannelTypeUID uid, boolean advanced, String itemType, Channe
* @param configDescriptionURI the link to the concrete ConfigDescription (could be null)
* @param autoUpdatePolicy the {@link AutoUpdatePolicy} to use.
* @throws IllegalArgumentException if the UID or the item type is null or empty,
* or the the meta information is null
* or the meta information is null
*/
public ChannelType(ChannelTypeUID uid, boolean advanced, String itemType, ChannelKind kind, String label,
String description, String category, Set<String> tags, StateDescription state, EventDescription event,
URI configDescriptionURI, AutoUpdatePolicy autoUpdatePolicy) throws IllegalArgumentException {
this(uid, advanced, itemType, kind, label, description, category, tags, state, null, event,
configDescriptionURI, autoUpdatePolicy);
}

private ChannelType(ChannelTypeUID uid, boolean advanced, String itemType, ChannelKind kind, String label,
String description, String category, Set<String> tags, StateDescription state,
List<CommandOption> commandOptions, EventDescription event, URI configDescriptionURI,
AutoUpdatePolicy autoUpdatePolicy) throws IllegalArgumentException {
super(uid, label, description);

if (kind == null) {
Expand All @@ -115,6 +156,11 @@ public ChannelType(ChannelTypeUID uid, boolean advanced, String itemType, Channe
this.advanced = advanced;
this.category = category;
this.state = state;
if (state == null && commandOptions != null) {
this.commandOptions = commandOptions;
} else {
this.commandOptions = null;
}
this.event = event;
this.autoUpdatePolicy = autoUpdatePolicy;
}
Expand Down Expand Up @@ -215,4 +261,8 @@ public AutoUpdatePolicy getAutoUpdatePolicy() {
return autoUpdatePolicy;
}

public List<CommandOption> getCommandOptions() {
return commandOptions;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@
*/
package org.eclipse.smarthome.core.thing.type;

import java.util.List;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.smarthome.core.types.CommandOption;
import org.eclipse.smarthome.core.types.StateDescription;

/**
Expand Down Expand Up @@ -41,4 +44,13 @@ public interface StateChannelTypeBuilder extends ChannelTypeBuilder<StateChannel
*/
StateChannelTypeBuilder withAutoUpdatePolicy(@Nullable AutoUpdatePolicy autoUpdatePolicy);

/**
* Sets the list of {@link CommandOption}s for the ChannelType
*
* @param commandOptions the list of {@link CommandOption}s
* @return this builder
*
*/
StateChannelTypeBuilder withCommandOptions(List<CommandOption> commandOptions);

}
Loading

0 comments on commit 3e03b67

Please sign in to comment.