diff --git a/bundles/org.openhab.binding.http/README.md b/bundles/org.openhab.binding.http/README.md index 980895f97bc7c..677ddb035806c 100644 --- a/bundles/org.openhab.binding.http/README.md +++ b/bundles/org.openhab.binding.http/README.md @@ -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 | diff --git a/bundles/org.openhab.binding.http/src/main/java/org/openhab/binding/http/internal/HttpThingHandler.java b/bundles/org.openhab.binding.http/src/main/java/org/openhab/binding/http/internal/HttpThingHandler.java index e522516f296a4..b18e3c119f269 100644 --- a/bundles/org.openhab.binding.http/src/main/java/org/openhab/binding/http/internal/HttpThingHandler.java +++ b/bundles/org.openhab.binding.http/src/main/java/org/openhab/binding/http/internal/HttpThingHandler.java @@ -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; @@ -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, diff --git a/bundles/org.openhab.binding.http/src/main/java/org/openhab/binding/http/internal/config/HttpChannelConfig.java b/bundles/org.openhab.binding.http/src/main/java/org/openhab/binding/http/internal/config/HttpChannelConfig.java index 9cebacc694ad9..2effb1a0b16bb 100644 --- a/bundles/org.openhab.binding.http/src/main/java/org/openhab/binding/http/internal/config/HttpChannelConfig.java +++ b/bundles/org.openhab.binding.http/src/main/java/org/openhab/binding/http/internal/config/HttpChannelConfig.java @@ -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; diff --git a/bundles/org.openhab.binding.http/src/main/java/org/openhab/binding/http/internal/converter/NumberItemConverter.java b/bundles/org.openhab.binding.http/src/main/java/org/openhab/binding/http/internal/converter/NumberItemConverter.java new file mode 100644 index 0000000000000..4f5d3f4039cc1 --- /dev/null +++ b/bundles/org.openhab.binding.http/src/main/java/org/openhab/binding/http/internal/converter/NumberItemConverter.java @@ -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 updateState, Consumer postCommand, + @Nullable Consumer 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(); + } +} diff --git a/bundles/org.openhab.binding.http/src/main/resources/OH-INF/config/config.xml b/bundles/org.openhab.binding.http/src/main/resources/OH-INF/config/config.xml index 51a51162deef2..0ee64f42ed961 100644 --- a/bundles/org.openhab.binding.http/src/main/resources/OH-INF/config/config.xml +++ b/bundles/org.openhab.binding.http/src/main/resources/OH-INF/config/config.xml @@ -202,6 +202,43 @@ + + + + This value is added to the base URL configured in the thing for retrieving values. + true + + + + This value is added to the base URL configured in the thing for sending values. + true + + + + Transformation pattern used when receiving values. + + + + Transformation pattern used when sending values. + + + + + + + + + true + true + READWRITE + + + + Unit to append to the (transformed) value. + true + + + diff --git a/bundles/org.openhab.binding.http/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.http/src/main/resources/OH-INF/thing/thing-types.xml index 61e14edb83b09..cf40b92a4f0a3 100644 --- a/bundles/org.openhab.binding.http/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.http/src/main/resources/OH-INF/thing/thing-types.xml @@ -142,7 +142,7 @@ Number - + diff --git a/bundles/org.openhab.binding.http/src/test/java/org/openhab/binding/http/internal/converter/ConverterTest.java b/bundles/org.openhab.binding.http/src/test/java/org/openhab/binding/http/internal/converter/ConverterTest.java index 7579cf2bc727f..fa8c60bf7a430 100644 --- a/bundles/org.openhab.binding.http/src/test/java/org/openhab/binding/http/internal/converter/ConverterTest.java +++ b/bundles/org.openhab.binding.http/src/test/java/org/openhab/binding/http/internal/converter/ConverterTest.java @@ -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 @@ -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);