| 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 | |
```java
Group G_heater "Zhimi Heater" <status>
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"}
```
--- /dev/null
+/**
+ * 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<String, Unit<?>> 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());
+ }
+}
@SerializedName("type")
@Expose
private @Nullable String type;
+ @SerializedName("unit")
+ @Expose
+ private @Nullable String unit;
@SerializedName("refresh")
@Expose
private @Nullable Boolean refresh;
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();
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;
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;
}
@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);
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;
}
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;
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()));
}
}
+ 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);
<label>Temperature</label>
<state pattern="%.1f" readOnly="true"/>
</channel-type>
+ <channel-type id="temperatureC">
+ <item-type>Number:Temperature</item-type>
+ <label>Temperature</label>
+ <state readOnly="true" pattern="%.1f %unit%"/>
+ </channel-type>
<channel-type id="humidity">
<item-type>Number</item-type>
<label>Humidity</label>
"property": "temperature",
"friendlyName": "Temperature",
"channel": "temperature",
- "channelType": "temperature",
- "type": "Number",
+ "channelType": "temperatureC",
+ "unit": "CELCIUS",
+ "type": "Number:Temperature",
"refresh": true,
"ChannelGroup": "",
"actions": []
"property": "target_temperature",
"friendlyName": "Target Temperature",
"channel": "target_temperature",
- "type": "Number",
+ "type": "Number:Temperature",
+ "channelType": "temperatureC",
"refresh": true,
"actions": [
{
"property": "temperature",
"friendlyName": "Temperature",
"channel": "temperature",
- "channelType": "temperature",
- "type": "Number",
+ "channelType": "temperatureC",
+ "type": "Number:Temperature",
"refresh": true,
"actions": []
},