diff --git a/bundles/org.openhab.binding.miio/README.md b/bundles/org.openhab.binding.miio/README.md index fdcff1a3e..ccb3ecb0c 100644 --- a/bundles/org.openhab.binding.miio/README.md +++ b/bundles/org.openhab.binding.miio/README.md @@ -3122,13 +3122,13 @@ e.g. `smarthome:send actionCommand 'upd_timer["1498595904821", "on"]'` would ena | Channel | Type | Description | Comment | |------------------|---------|-------------------------------------|------------| | power | Switch | Power | | -| target_temperature | Number | Target Temperature | | +| target_temperature | Number:Temperature | Target Temperature | | | brightness | Number | Brightness | | | buzzer | Switch | Buzzer Status | | | relative_humidity | Number | Relative Humidity | | | childlock | Switch | Child Lock | | | HWSwitch | Switch | HW Switch | | -| temperature | Number | Temperature | | +| temperature | Number:Temperature | Temperature | | | usedhours | Number | Run Time | | @@ -6429,13 +6429,13 @@ note: Autogenerated example. Replace the id (heater) in the channel with your ow ```java Group G_heater "Zhimi Heater" Switch power "Power" (G_heater) {channel="miio:basic:heater:power"} -Number target_temperature "Target Temperature" (G_heater) {channel="miio:basic:heater:target_temperature"} +Number:Temperature target_temperature "Target Temperature" (G_heater) {channel="miio:basic:heater:target_temperature"} Number brightness "Brightness" (G_heater) {channel="miio:basic:heater:brightness"} Switch buzzer "Buzzer Status" (G_heater) {channel="miio:basic:heater:buzzer"} Number relative_humidity "Relative Humidity" (G_heater) {channel="miio:basic:heater:relative_humidity"} Switch childlock "Child Lock" (G_heater) {channel="miio:basic:heater:childlock"} Switch HWSwitch "HW Switch" (G_heater) {channel="miio:basic:heater:HWSwitch"} -Number temperature "Temperature" (G_heater) {channel="miio:basic:heater:temperature"} +Number:Temperature temperature "Temperature" (G_heater) {channel="miio:basic:heater:temperature"} Number usedhours "Run Time" (G_heater) {channel="miio:basic:heater:usedhours"} ``` diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoQuantiyTypes.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoQuantiyTypes.java new file mode 100644 index 000000000..303c62bab --- /dev/null +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoQuantiyTypes.java @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2010-2020 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.miio.internal; + +import java.util.Arrays; +import java.util.Map; +import java.util.stream.Collectors; + +import javax.measure.Unit; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.core.library.unit.ImperialUnits; +import org.openhab.core.library.unit.SIUnits; +import org.openhab.core.library.unit.SmartHomeUnits; + +/** + * Enum of the units used in the miio protocol + * Used to find the right {@link javax.measure.Unit} given the string of the unit + * + * @author Marcel Verpaalen - Initial contribution + */ +@NonNullByDefault +public enum MiIoQuantiyTypes { + + CELCIUS(SIUnits.CELSIUS), + FAHRENHEIT(ImperialUnits.FAHRENHEIT), + SECOND(SmartHomeUnits.SECOND), + MINUTE(SmartHomeUnits.MINUTE), + HOUR(SmartHomeUnits.HOUR), + AMPERE(SmartHomeUnits.AMPERE), + WATT(SmartHomeUnits.WATT); + + private final Unit unit; + + private static Map> stringMap = Arrays.stream(values()) + .collect(Collectors.toMap(Enum::toString, MiIoQuantiyTypes::getUnit)); + + private MiIoQuantiyTypes(Unit unit) { + this.unit = unit; + } + + public Unit getUnit() { + return unit; + } + + public static @Nullable Unit get(String unitName) { + return stringMap.get(unitName.toUpperCase()); + } +} diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/basic/MiIoBasicChannel.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/basic/MiIoBasicChannel.java index 27b1bf52d..89994ec66 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/basic/MiIoBasicChannel.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/basic/MiIoBasicChannel.java @@ -53,6 +53,9 @@ public class MiIoBasicChannel { @SerializedName("type") @Expose private @Nullable String type; + @SerializedName("unit") + @Expose + private @Nullable String unit; @SerializedName("refresh") @Expose private @Nullable Boolean refresh; @@ -155,6 +158,15 @@ public class MiIoBasicChannel { this.type = type; } + public String getUnit() { + final @Nullable String unit = this.unit; + return unit != null ? unit : ""; + } + + public void setUnit(String unit) { + this.unit = unit; + } + public Boolean getRefresh() { final @Nullable Boolean rf = refresh; return rf != null && rf.booleanValue() && !getProperty().isEmpty(); diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoBasicHandler.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoBasicHandler.java index ee6422b33..63f1929da 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoBasicHandler.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoBasicHandler.java @@ -23,11 +23,15 @@ import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; +import javax.measure.Unit; +import javax.measure.format.ParserException; + import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.miio.internal.MiIoBindingConfiguration; import org.openhab.binding.miio.internal.MiIoCommand; import org.openhab.binding.miio.internal.MiIoCryptoException; +import org.openhab.binding.miio.internal.MiIoQuantiyTypes; import org.openhab.binding.miio.internal.MiIoSendCommand; import org.openhab.binding.miio.internal.Utils; import org.openhab.binding.miio.internal.basic.ActionConditions; @@ -44,7 +48,10 @@ import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.HSBType; import org.openhab.core.library.types.OnOffType; import org.openhab.core.library.types.PercentType; +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.SmartHomeUnits; import org.openhab.core.thing.Channel; import org.openhab.core.thing.ChannelUID; import org.openhab.core.thing.Thing; @@ -105,7 +112,8 @@ public class MiIoBasicHandler extends MiIoAbstractHandler { } @Override - public void handleCommand(ChannelUID channelUID, Command command) { + public void handleCommand(ChannelUID channelUID, Command receivedCommand) { + Command command = receivedCommand; if (command == RefreshType.REFRESH) { if (updateDataCache.isExpired()) { logger.debug("Refreshing {}", channelUID); @@ -119,7 +127,7 @@ public class MiIoBasicHandler extends MiIoAbstractHandler { cmds.put(sendCommand(command.toString()), command.toString()); return; } - logger.debug("Locating action for channel '{}': '{}'", channelUID.getId(), command); + logger.debug("Locating action for {} channel '{}': '{}'", getThing().getUID(), channelUID.getId(), command); if (!actions.isEmpty()) { if (actions.containsKey(channelUID)) { int valuePos = 0; @@ -137,6 +145,25 @@ public class MiIoBasicHandler extends MiIoAbstractHandler { } String cmd = action.getCommand(); CommandParameterType paramType = action.getparameterType(); + if (command instanceof QuantityType) { + QuantityType qtc = null; + try { + if (!miIoBasicChannel.getUnit().isBlank()) { + Unit unit = MiIoQuantiyTypes.get(miIoBasicChannel.getUnit()); + if (unit != null) { + qtc = ((QuantityType) command).toUnit(unit); + } + } + } catch (ParserException e) { + // swallow + } + if (qtc != null) { + command = new DecimalType(qtc.toBigDecimal()); + } else { + logger.debug("Could not convert QuantityType to '{}'", miIoBasicChannel.getUnit()); + command = new DecimalType(((QuantityType) command).toBigDecimal()); + } + } if (paramType == CommandParameterType.COLOR) { if (command instanceof HSBType) { HSBType hsb = (HSBType) command; @@ -505,9 +532,10 @@ public class MiIoBasicHandler extends MiIoAbstractHandler { val = transformed; } try { - switch (basicChannel.getType().toLowerCase()) { + String[] chType = basicChannel.getType().toLowerCase().split(":"); + switch (chType[0]) { case "number": - updateState(basicChannel.getChannel(), new DecimalType(val.getAsBigDecimal())); + quantityTypeUpdate(basicChannel, val, chType.length > 1 ? chType[1] : ""); break; case "dimmer": updateState(basicChannel.getChannel(), new PercentType(val.getAsBigDecimal())); @@ -534,6 +562,39 @@ public class MiIoBasicHandler extends MiIoAbstractHandler { } } + private void quantityTypeUpdate(MiIoBasicChannel basicChannel, JsonElement val, String type) { + if (!basicChannel.getUnit().isBlank()) { + Unit unit = MiIoQuantiyTypes.get(basicChannel.getUnit()); + if (unit != null) { + logger.debug("'{}' channel '{}' has unit '{}' with symbol '{}'.", getThing().getUID(), + basicChannel.getChannel(), basicChannel.getUnit(), unit); + updateState(basicChannel.getChannel(), new QuantityType<>(val.getAsBigDecimal(), unit)); + } else { + logger.debug("Unit '{}' used by '{}' channel '{}' is not found.. using default unit.", + getThing().getUID(), basicChannel.getUnit(), basicChannel.getChannel()); + } + } + // if no unit is provided or unit not found use default units, these units have so far been seen for miio + // devices + switch (type.toLowerCase()) { + case "temperature": + updateState(basicChannel.getChannel(), new QuantityType<>(val.getAsBigDecimal(), SIUnits.CELSIUS)); + break; + case "electriccurrent": + updateState(basicChannel.getChannel(), + new QuantityType<>(val.getAsBigDecimal(), SmartHomeUnits.AMPERE)); + break; + case "energy": + updateState(basicChannel.getChannel(), new QuantityType<>(val.getAsBigDecimal(), SmartHomeUnits.WATT)); + break; + case "time": + updateState(basicChannel.getChannel(), new QuantityType<>(val.getAsBigDecimal(), SmartHomeUnits.HOUR)); + break; + default: + updateState(basicChannel.getChannel(), new DecimalType(val.getAsBigDecimal())); + } + } + @Override public void onMessageReceived(MiIoSendCommand response) { super.onMessageReceived(response); diff --git a/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/thing/commonChannels.xml b/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/thing/commonChannels.xml index 8a8ce289b..27cbfcbbb 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/thing/commonChannels.xml +++ b/bundles/org.openhab.binding.miio/src/main/resources/OH-INF/thing/commonChannels.xml @@ -154,6 +154,11 @@ + + Number:Temperature + + + Number diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/chuangmi.plug.v3fw.json b/bundles/org.openhab.binding.miio/src/main/resources/database/chuangmi.plug.v3fw.json index c3e5f6308..3db10fc8c 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/chuangmi.plug.v3fw.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/chuangmi.plug.v3fw.json @@ -42,8 +42,9 @@ "property": "temperature", "friendlyName": "Temperature", "channel": "temperature", - "channelType": "temperature", - "type": "Number", + "channelType": "temperatureC", + "unit": "CELCIUS", + "type": "Number:Temperature", "refresh": true, "ChannelGroup": "", "actions": [] diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.heater.za1.json b/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.heater.za1.json index fb20b97da..a37fb2e72 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.heater.za1.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/zhimi.heater.za1.json @@ -24,7 +24,8 @@ "property": "target_temperature", "friendlyName": "Target Temperature", "channel": "target_temperature", - "type": "Number", + "type": "Number:Temperature", + "channelType": "temperatureC", "refresh": true, "actions": [ { @@ -100,8 +101,8 @@ "property": "temperature", "friendlyName": "Temperature", "channel": "temperature", - "channelType": "temperature", - "type": "Number", + "channelType": "temperatureC", + "type": "Number:Temperature", "refresh": true, "actions": [] },