]> git.basschouten.com Git - openhab-addons.git/commitdiff
[http] enable UoM for number channels (#9601)
authorJ-N-K <J-N-K@users.noreply.github.com>
Wed, 6 Jan 2021 21:12:31 +0000 (22:12 +0100)
committerGitHub <noreply@github.com>
Wed, 6 Jan 2021 21:12:31 +0000 (22:12 +0100)
* add unit

Signed-off-by: Jan N. Klug <jan.n.klug@rub.de>
* documentation an XML

Signed-off-by: Jan N. Klug <jan.n.klug@rub.de>
* address review comments

Signed-off-by: Jan N. Klug <jan.n.klug@rub.de>
* improvements

Signed-off-by: Jan N. Klug <jan.n.klug@rub.de>
* improvements

Signed-off-by: Jan N. Klug <jan.n.klug@rub.de>
bundles/org.openhab.binding.http/README.md
bundles/org.openhab.binding.http/src/main/java/org/openhab/binding/http/internal/HttpThingHandler.java
bundles/org.openhab.binding.http/src/main/java/org/openhab/binding/http/internal/config/HttpChannelConfig.java
bundles/org.openhab.binding.http/src/main/java/org/openhab/binding/http/internal/converter/NumberItemConverter.java [new file with mode: 0644]
bundles/org.openhab.binding.http/src/main/resources/OH-INF/config/config.xml
bundles/org.openhab.binding.http/src/main/resources/OH-INF/thing/thing-types.xml
bundles/org.openhab.binding.http/src/test/java/org/openhab/binding/http/internal/converter/ConverterTest.java

index 980895f97bc7cc137ccf38b5a085d99de5680aec..677ddb035806cf95a9f79becc8555d88b38576d2 100644 (file)
@@ -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 |
index e522516f296a4d32632075d1a0c0ad90aca85043..b18e3c119f2691e2f0ca16e51fd949356283793e 100644 (file)
@@ -33,19 +33,10 @@ import org.eclipse.jetty.http.HttpMethod;
 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 @@ public class HttpThingHandler extends BaseThingHandler {
                 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,
index 9cebacc694ad987615f9ee4a38d09299b1a15297..2effb1a0b16bbcd119ca2a18bf951175dc8c40f1 100644 (file)
@@ -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 (file)
index 0000000..4f5d3f4
--- /dev/null
@@ -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();
+    }
+}
index 51a51162deef2bedb6c2b5eb605418b5b63111e3..0ee64f42ed96183ee3bbae2c00323416a7a0b133 100644 (file)
                </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>
index 61e14edb83b095cf1ddbe926750ac16cd81e7f0c..cf40b92a4f0a38398bc91ec19786fbf1da94db69 100644 (file)
        <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">
index 7579cf2bc727f7f79667cd233b40c9d7dd6a7953..fa8c60bf7a4302487d8307ec41804fba5a635513 100644 (file)
@@ -21,9 +21,13 @@ import org.openhab.binding.http.internal.config.HttpChannelConfig;
 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 @@ import org.openhab.core.types.State;
 @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);