Skip to content

Commit

Permalink
[http] enable UoM for number channels (#9601)
Browse files Browse the repository at this point in the history
* add unit

Signed-off-by: Jan N. Klug <[email protected]>

* documentation an XML

Signed-off-by: Jan N. Klug <[email protected]>

* address review comments

Signed-off-by: Jan N. Klug <[email protected]>

* improvements

Signed-off-by: Jan N. Klug <[email protected]>

* improvements

Signed-off-by: Jan N. Klug <[email protected]>
  • Loading branch information
J-N-K authored Jan 6, 2021
1 parent cb5d659 commit 1480c41
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 13 deletions.
10 changes: 10 additions & 0 deletions bundles/org.openhab.binding.http/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,16 @@ All values that are not `onValue`, `offValue`, `increaseValue`, `decreaseValue`

All values that are not `onValue`, `offValue`, `increaseValue`, `decreaseValue` are interpreted as brightness 0-100% and need to be numeric only.

### `number`

| parameter | optional | default | description |
|-------------------------|----------|-------------|-------------|
| `unit` | yes | - | The unit label for this channel |

`number` channels can be used for `DecimalType` or `QuantityType` values.
If a unit is given in the `unit` parameter, the binding tries to create a `QuantityType` state before updating the channel, if no unit is present, it creates a `DecimalType`.
Please note that incompatible units (e.g. `°C` for a `Number:Density` item) will fail silently, i.e. no error message is logged even if the state update fails.

### `player`

| parameter | optional | default | description |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,10 @@
import org.openhab.binding.http.internal.config.HttpChannelConfig;
import org.openhab.binding.http.internal.config.HttpChannelMode;
import org.openhab.binding.http.internal.config.HttpThingConfig;
import org.openhab.binding.http.internal.converter.AbstractTransformingItemConverter;
import org.openhab.binding.http.internal.converter.ColorItemConverter;
import org.openhab.binding.http.internal.converter.DimmerItemConverter;
import org.openhab.binding.http.internal.converter.FixedValueMappingItemConverter;
import org.openhab.binding.http.internal.converter.GenericItemConverter;
import org.openhab.binding.http.internal.converter.ImageItemConverter;
import org.openhab.binding.http.internal.converter.ItemValueConverter;
import org.openhab.binding.http.internal.converter.PlayerItemConverter;
import org.openhab.binding.http.internal.converter.RollershutterItemConverter;
import org.openhab.binding.http.internal.converter.*;
import org.openhab.binding.http.internal.http.*;
import org.openhab.binding.http.internal.transform.ValueTransformationProvider;
import org.openhab.core.library.types.DateTimeType;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.PointType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.thing.Channel;
Expand Down Expand Up @@ -260,8 +251,8 @@ private void createChannel(Channel channel) {
itemValueConverter = createGenericItemConverter(commandUrl, channelUID, channelConfig, PointType::new);
break;
case "Number":
itemValueConverter = createGenericItemConverter(commandUrl, channelUID, channelConfig,
DecimalType::new);
itemValueConverter = createItemConverter(NumberItemConverter::new, commandUrl, channelUID,
channelConfig);
break;
case "Player":
itemValueConverter = createItemConverter(PlayerItemConverter::new, commandUrl, channelUID,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ public class HttpChannelConfig {

public HttpChannelMode mode = HttpChannelMode.READWRITE;

// number
public @Nullable String unit;

// switch, dimmer, color
public @Nullable String onValue;
public @Nullable String offValue;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/**
* 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.http.internal.converter;

import java.util.function.Consumer;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.http.internal.config.HttpChannelConfig;
import org.openhab.binding.http.internal.transform.ValueTransformation;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;

/**
* The {@link NumberItemConverter} implements {@link org.openhab.core.library.items.NumberItem} conversions
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class NumberItemConverter extends AbstractTransformingItemConverter {

public NumberItemConverter(Consumer<State> updateState, Consumer<Command> postCommand,
@Nullable Consumer<String> sendHttpValue, ValueTransformation stateTransformations,
ValueTransformation commandTransformations, HttpChannelConfig channelConfig) {
super(updateState, postCommand, sendHttpValue, stateTransformations, commandTransformations, channelConfig);
}

@Override
protected @Nullable Command toCommand(String value) {
return null;
}

@Override
protected State toState(String value) {
String trimmedValue = value.trim();
if (!trimmedValue.isEmpty()) {
try {
if (channelConfig.unit != null) {
// we have a given unit - use that
return new QuantityType<>(trimmedValue + " " + channelConfig.unit);
} else {
try {
// try if we have a simple number
return new DecimalType(trimmedValue);
} catch (IllegalArgumentException e1) {
// not a plain number, maybe with unit?
return new QuantityType<>(trimmedValue);
}
}
} catch (IllegalArgumentException e) {
// finally failed
}
}
return UnDefType.UNDEF;
}

@Override
protected String toString(Command command) {
return command.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,43 @@
</parameter>
</config-description>

<config-description uri="channel-type:http:channel-config-number">
<parameter name="stateExtension" type="text">
<label>State URL Extension</label>
<description>This value is added to the base URL configured in the thing for retrieving values.</description>
<advanced>true</advanced>
</parameter>
<parameter name="commandExtension" type="text">
<label>Command URL Extension</label>
<description>This value is added to the base URL configured in the thing for sending values.</description>
<advanced>true</advanced>
</parameter>
<parameter name="stateTransformation" type="text">
<label>State Transformation</label>
<description>Transformation pattern used when receiving values.</description>
</parameter>
<parameter name="commandTransformation" type="text">
<label>Command Transformation</label>
<description>Transformation pattern used when sending values.</description>
</parameter>
<parameter name="mode" type="text">
<label>Read/Write Mode</label>
<options>
<option value="READWRITE">Read/Write</option>
<option value="READONLY">Read Only</option>
<option value="WRITEONLY">Write Only</option>
</options>
<limitToOptions>true</limitToOptions>
<advanced>true</advanced>
<default>READWRITE</default>
</parameter>
<parameter name="unit" type="text">
<label>Unit</label>
<description>Unit to append to the (transformed) value.</description>
<advanced>true</advanced>
</parameter>
</config-description>

<config-description uri="channel-type:http:channel-config-player">
<parameter name="stateExtension" type="text">
<label>State URL Extension</label>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@
<channel-type id="number">
<item-type>Number</item-type>
<label>Number Channel</label>
<config-description-ref uri="channel-type:http:channel-config"/>
<config-description-ref uri="channel-type:http:channel-config-number"/>
</channel-type>

<channel-type id="player">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,13 @@
import org.openhab.binding.http.internal.transform.NoOpValueTransformation;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.PointType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.library.unit.Units;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;

/**
* The {@link ConverterTest} is a test class for state converters
Expand All @@ -33,6 +37,40 @@
@NonNullByDefault
public class ConverterTest {

@Test
public void numberItemConverter() {
NumberItemConverter converter = new NumberItemConverter(this::updateState, this::postCommand,
this::sendHttpValue, NoOpValueTransformation.getInstance(), NoOpValueTransformation.getInstance(),
new HttpChannelConfig());

// without unit
Assertions.assertEquals(new DecimalType(1234), converter.toState("1234"));

// unit in transformation result
Assertions.assertEquals(new QuantityType<>(100, SIUnits.CELSIUS), converter.toState("100°C"));

// no valid value
Assertions.assertEquals(UnDefType.UNDEF, converter.toState("W"));
Assertions.assertEquals(UnDefType.UNDEF, converter.toState(""));
}

@Test
public void numberItemConverterWithUnit() {
HttpChannelConfig channelConfig = new HttpChannelConfig();
channelConfig.unit = "W";
NumberItemConverter converter = new NumberItemConverter(this::updateState, this::postCommand,
this::sendHttpValue, NoOpValueTransformation.getInstance(), NoOpValueTransformation.getInstance(),
channelConfig);

// without unit
Assertions.assertEquals(new QuantityType<>(500, Units.WATT), converter.toState("500"));

// no valid value
Assertions.assertEquals(UnDefType.UNDEF, converter.toState("100°C"));
Assertions.assertEquals(UnDefType.UNDEF, converter.toState("foo"));
Assertions.assertEquals(UnDefType.UNDEF, converter.toState(""));
}

@Test
public void stringTypeConverter() {
GenericItemConverter converter = createConverter(StringType::new);
Expand Down

0 comments on commit 1480c41

Please sign in to comment.