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

Unit hint in thing channels #4079

Merged
merged 5 commits into from
Apr 6, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
* @author Yannick Schaus - Added filter to getAll
* @author Markus Rathgeb - Migrated to JAX-RS Whiteboard Specification
* @author Wouter Born - Migrated to OpenAPI annotations
* @author Mark Herwege - added unit hint
*/
@Component
@JaxrsResource
Expand Down Expand Up @@ -199,8 +200,8 @@ private ChannelTypeDTO convertToChannelTypeDTO(ChannelType channelType, Locale l
: configDescriptionDTO.parameterGroups;

return new ChannelTypeDTO(channelType.getUID().toString(), channelType.getLabel(), channelType.getDescription(),
channelType.getCategory(), channelType.getItemType(), channelType.getKind(), parameters,
parameterGroups, channelType.getState(), channelType.getTags(), channelType.isAdvanced(),
channelType.getCategory(), channelType.getItemType(), channelType.getUnitHint(), channelType.getKind(),
parameters, parameterGroups, channelType.getState(), channelType.getTags(), channelType.isAdvanced(),
channelType.getCommandDescription());
}
}
2 changes: 1 addition & 1 deletion bundles/org.openhab.core.thing/schema/catalog.cat
Original file line number Diff line number Diff line change
@@ -1 +1 @@
REWRITE_SYSTEM "https://openhab.org/schemas" "file:${project.basedir}/xsd/thing"
REWRITE_SYSTEM "https://openhab.org/schemas" "thing"
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@

<xs:complexType name="channelType">
<xs:sequence>
<xs:element name="item-type" type="xs:string" minOccurs="0"/>
<xs:element name="item-type" type="thing-description:itemType" minOccurs="0"/>
<xs:element name="kind" type="xs:string" minOccurs="0"/>
<xs:element name="label" type="xs:string"/>
<xs:element name="description" type="xs:string" minOccurs="0"/>
Expand Down Expand Up @@ -141,6 +141,14 @@
<xs:attribute name="typeId" type="config-description:idRestrictionPattern" use="required"/>
</xs:complexType>

<xs:complexType name="itemType">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="unitHint" type="xs:string" use="optional" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>

<xs:complexType name="tags">
<xs:sequence>
<xs:element name="tag" type="xs:string" minOccurs="1" maxOccurs="unbounded"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
* This is a data transfer object that is used with to serialize channel types.
*
* @author Chris Jackson - Initial contribution
* @author Mark Herwege - added unit hint
*/
public class ChannelTypeDTO {

Expand All @@ -34,6 +35,7 @@ public class ChannelTypeDTO {
public String label;
public String category;
public String itemType;
public String unitHint;
public String kind;
public StateDescription stateDescription;
public Set<String> tags;
Expand All @@ -45,7 +47,7 @@ public ChannelTypeDTO() {
}

public ChannelTypeDTO(String uid, String label, String description, String category, String itemType,
ChannelKind kind, List<ConfigDescriptionParameterDTO> parameters,
String unitHint, ChannelKind kind, List<ConfigDescriptionParameterDTO> parameters,
List<ConfigDescriptionParameterGroupDTO> parameterGroups, StateDescription stateDescription,
Set<String> tags, boolean advanced, CommandDescription commandDescription) {
this.UID = uid;
Expand All @@ -58,6 +60,7 @@ public ChannelTypeDTO(String uid, String label, String description, String categ
this.tags = tags;
this.kind = kind.toString();
this.itemType = itemType;
this.unitHint = unitHint;
this.advanced = advanced;
this.commandDescription = commandDescription;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
* @author Christoph Weitkamp - factored out from {@link org.openhab.core.thing.xml.internal.XmlChannelTypeProvider} and
* {@link org.openhab.core.thing.xml.internal.XmlChannelGroupTypeProvider}
* @author Henning Treu - factored out from {@link ThingTypeI18nLocalizationService}
* @author Mark Herwege - added unit hint
*/
@Component(service = ChannelTypeI18nLocalizationService.class)
@NonNullByDefault
Expand Down Expand Up @@ -146,9 +147,10 @@ public ChannelType createLocalizedChannelType(Bundle bundle, ChannelType channel
if (itemType == null || itemType.isBlank()) {
throw new IllegalArgumentException("If the kind is 'state', the item type must be set!");
}
String unitHint = channelType.getUnitHint();

builder = ChannelTypeBuilder.state(channelTypeUID, label == null ? defaultLabel : label, itemType)
.withStateDescriptionFragment(stateDescriptionFragment)
.withUnitHint(unitHint).withStateDescriptionFragment(stateDescriptionFragment)
.withAutoUpdatePolicy(channelType.getAutoUpdatePolicy()).withCommandDescription(command);
break;
case TRIGGER:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,23 +30,25 @@
* StateChannelTypeBuilder to create {@link ChannelType}s of kind STATE
*
* @author Stefan Triller - Initial contribution
* @author Mark Herwege - added unit hint
*/
@NonNullByDefault
public class StateChannelTypeBuilderImpl extends AbstractChannelTypeBuilder<StateChannelTypeBuilder>
implements StateChannelTypeBuilder {

private static class StateChannelTypeImpl extends ChannelType {
private StateChannelTypeImpl(ChannelTypeUID uid, boolean advanced, String itemType, String label,
@Nullable String description, @Nullable String category, @Nullable Set<String> tags,
private StateChannelTypeImpl(ChannelTypeUID uid, boolean advanced, String itemType, @Nullable String unitHint,
String label, @Nullable String description, @Nullable String category, @Nullable Set<String> tags,
@Nullable StateDescription state, @Nullable CommandDescription commandDescription,
@Nullable URI configDescriptionURI, @Nullable AutoUpdatePolicy autoUpdatePolicy)
throws IllegalArgumentException {
super(uid, advanced, itemType, ChannelKind.STATE, label, description, category, tags, state,
super(uid, advanced, itemType, unitHint, ChannelKind.STATE, label, description, category, tags, state,
commandDescription, null, configDescriptionURI, autoUpdatePolicy);
}
}

private final String itemType;
private @Nullable String unitHint;
private @Nullable StateDescriptionFragment stateDescriptionFragment;
private @Nullable AutoUpdatePolicy autoUpdatePolicy;
private @Nullable CommandDescription commandDescription;
Expand All @@ -61,6 +63,12 @@ public StateChannelTypeBuilderImpl(ChannelTypeUID channelTypeUID, String label,
this.itemType = itemType;
}

@Override
public StateChannelTypeBuilder withUnitHint(@Nullable String unitHint) {
this.unitHint = unitHint;
return this;
}

@Override
public StateChannelTypeBuilder withStateDescriptionFragment(
@Nullable StateDescriptionFragment stateDescriptionFragment) {
Expand All @@ -82,8 +90,8 @@ public StateChannelTypeBuilder withCommandDescription(@Nullable CommandDescripti

@Override
public ChannelType build() {
return new StateChannelTypeImpl(channelTypeUID, advanced, itemType, label, description, category, tags,
stateDescriptionFragment != null ? stateDescriptionFragment.toStateDescription() : null,
return new StateChannelTypeImpl(channelTypeUID, advanced, itemType, unitHint, label, description, category,
tags, stateDescriptionFragment != null ? stateDescriptionFragment.toStateDescription() : null,
commandDescription, configDescriptionURI, autoUpdatePolicy);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ private static class TriggerChannelTypeImpl extends ChannelType {
TriggerChannelTypeImpl(ChannelTypeUID uid, boolean advanced, String label, @Nullable String description,
@Nullable String category, @Nullable Set<String> tags, @Nullable EventDescription event,
@Nullable URI configDescriptionURI) throws IllegalArgumentException {
super(uid, advanced, null, ChannelKind.TRIGGER, label, description, category, tags, null, null, event,
super(uid, advanced, null, null, ChannelKind.TRIGGER, label, description, category, tags, null, null, event,
configDescriptionURI, null);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
*
* @author Michael Grammling - Initial contribution
* @author Henning Treu - add command options
* @author Mark Herwege - added unit hint
*/
@NonNullByDefault
public class ChannelType extends AbstractDescriptionType {
Expand All @@ -43,6 +44,7 @@ public class ChannelType extends AbstractDescriptionType {
private final @Nullable String category;
private final @Nullable StateDescription state;
private final @Nullable CommandDescription commandDescription;
private final @Nullable String unitHint;
private final @Nullable EventDescription event;
private final @Nullable AutoUpdatePolicy autoUpdatePolicy;

Expand All @@ -68,11 +70,12 @@ public class ChannelType extends AbstractDescriptionType {
* @throws IllegalArgumentException if the UID or the item type is null or empty,
* or the meta information is null
*/
protected ChannelType(ChannelTypeUID uid, boolean advanced, @Nullable String itemType, ChannelKind kind,
String label, @Nullable String description, @Nullable String category, @Nullable Set<String> tags,
@Nullable StateDescription state, @Nullable CommandDescription commandDescription,
@Nullable EventDescription event, @Nullable URI configDescriptionURI,
@Nullable AutoUpdatePolicy autoUpdatePolicy) throws IllegalArgumentException {
protected ChannelType(ChannelTypeUID uid, boolean advanced, @Nullable String itemType, @Nullable String unitHint,
ChannelKind kind, String label, @Nullable String description, @Nullable String category,
@Nullable Set<String> tags, @Nullable StateDescription state,
@Nullable CommandDescription commandDescription, @Nullable EventDescription event,
@Nullable URI configDescriptionURI, @Nullable AutoUpdatePolicy autoUpdatePolicy)
throws IllegalArgumentException {
super(uid, label, description, configDescriptionURI);

if (kind == ChannelKind.STATE && (itemType == null || itemType.isBlank())) {
Expand All @@ -83,6 +86,7 @@ protected ChannelType(ChannelTypeUID uid, boolean advanced, @Nullable String ite
}

this.itemType = itemType;
this.unitHint = unitHint;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general LGTM. Would it make sense to throw an IAE here when the item-type is not Number:* (similar to l. 85 above)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, makes sense. Done.

this.kind = kind;

this.tags = tags == null ? Set.of() : Set.copyOf(tags);
Expand Down Expand Up @@ -141,6 +145,16 @@ public String toString() {
return state;
}

/**
* Returns the {@link unitHint} of a channel which gives information on what unit to suggest when creating an item
* linked to the channel.
*
* @return the {@link unitHint}
*/
public @Nullable String getUnitHint() {
return unitHint;
}

/**
* Returns information about the supported events.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
* Interface for builders for {@link ChannelType}s of kind STATE
*
* @author Stefan Triller - Initial contribution
* @author Mark Herwege - added unit hint
*/
@NonNullByDefault
public interface StateChannelTypeBuilder extends ChannelTypeBuilder<StateChannelTypeBuilder> {
Expand All @@ -48,4 +49,12 @@ public interface StateChannelTypeBuilder extends ChannelTypeBuilder<StateChannel
* @return this builder
*/
StateChannelTypeBuilder withCommandDescription(@Nullable CommandDescription commandDescription);

/**
* Sets the unitHint for the {@link ChannelType}
*
* @param unitHint the unit hint
* @return this builder
*/
StateChannelTypeBuilder withUnitHint(@Nullable String unitHint);
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,14 @@
*
* @author Michael Grammling - Initial contribution
* @author Ivan Iliev - Added support for system wide channel types
* @author Mark Herwege - added unit hint
*/
@NonNullByDefault
public class ChannelTypeConverter extends AbstractDescriptionTypeConverter<ChannelTypeXmlResult> {

record ItemType(@Nullable String itemType, @Nullable String unitHint) {
}

public ChannelTypeConverter() {
super(ChannelTypeXmlResult.class, "channel-type");
attributeMapValidator = new ConverterAttributeMapValidator(
Expand All @@ -73,8 +77,15 @@ private boolean readBoolean(Map<String, String> attributes, String attributeName
return defaultValue;
}

private @Nullable String readItemType(NodeIterator nodeIterator) throws ConversionException {
return (String) nodeIterator.nextValue("item-type", false);
private ItemType readItemType(NodeIterator nodeIterator) throws ConversionException {
Object next = nodeIterator.next("item-type", false);
if (next instanceof NodeValue nodeValue) {
String itemType = (String) nodeValue.getValue();
Map<String, String> attributes = nodeValue.getAttributes();
String unitHint = attributes != null ? attributes.get("unitHint") : null;
return new ItemType(itemType, unitHint);
}
return new ItemType(null, null);
}

private @Nullable String readKind(NodeIterator nodeIterator) throws ConversionException {
Expand Down Expand Up @@ -171,7 +182,10 @@ private boolean readBoolean(Map<String, String> attributes, String attributeName
String uid = system ? XmlHelper.getSystemUID(super.getID(attributes)) : super.getUID(attributes, context);
ChannelTypeUID channelTypeUID = new ChannelTypeUID(uid);

String itemType = readItemType(nodeIterator);
ItemType type = readItemType(nodeIterator);
String itemType = type.itemType();
String unitHint = type.unitHint();

String kind = readKind(nodeIterator);
String label = super.readLabel(nodeIterator);
String description = super.readDescription(nodeIterator);
Expand Down Expand Up @@ -203,7 +217,7 @@ private boolean readBoolean(Map<String, String> attributes, String attributeName
builder = ChannelTypeBuilder.state(channelTypeUID, label, itemType).isAdvanced(advanced)
.withConfigDescriptionURI(configDescriptionURI)
.withStateDescriptionFragment(stateDescriptionFragment).withAutoUpdatePolicy(autoUpdatePolicy)
.withCommandDescription(commandDescription);
.withCommandDescription(commandDescription).withUnitHint(unitHint);
} else if (cKind == ChannelKind.TRIGGER) {
TriggerChannelTypeBuilder triggerChannelTypeBuilder = ChannelTypeBuilder.trigger(channelTypeUID, label)
.isAdvanced(advanced).withConfigDescriptionURI(configDescriptionURI);
Expand Down
Loading