Add new channels for water and power consumption for washing machines and dishwashers. (#11298)
Fixes #11297 Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
This commit is contained in:
parent
8440745ceb
commit
27383fcd64
|
@ -0,0 +1,49 @@
|
||||||
|
/**
|
||||||
|
* 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.miele.internal;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link ExtendedDeviceStateUtil} class contains utility methods for parsing
|
||||||
|
* ExtendedDeviceState information
|
||||||
|
*
|
||||||
|
* @author Jacob Laursen - Added power/water consumption channels
|
||||||
|
*/
|
||||||
|
public class ExtendedDeviceStateUtil {
|
||||||
|
private static final byte[] HEX_ARRAY = "0123456789ABCDEF".getBytes(StandardCharsets.US_ASCII);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert byte array to hex representation.
|
||||||
|
*/
|
||||||
|
public static String bytesToHex(byte[] bytes) {
|
||||||
|
byte[] hexChars = new byte[bytes.length * 2];
|
||||||
|
for (int j = 0; j < bytes.length; j++) {
|
||||||
|
int v = bytes[j] & 0xFF;
|
||||||
|
hexChars[j * 2] = HEX_ARRAY[v >>> 4];
|
||||||
|
hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
|
||||||
|
}
|
||||||
|
|
||||||
|
return new String(hexChars, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert string consisting of 8 bit characters to byte array.
|
||||||
|
* Note: This simple operation has been extracted and pure here to document
|
||||||
|
* and ensure correct behavior for 8 bit characters that should be turned
|
||||||
|
* into single bytes without any UTF-8 encoding.
|
||||||
|
*/
|
||||||
|
public static byte[] stringToBytes(String input) {
|
||||||
|
return input.getBytes(StandardCharsets.ISO_8859_1);
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,6 +31,11 @@ public class MieleBindingConstants {
|
||||||
public static final String DEVICE_CLASS = "dc";
|
public static final String DEVICE_CLASS = "dc";
|
||||||
public static final String PROTOCOL_PROPERTY_NAME = "protocol";
|
public static final String PROTOCOL_PROPERTY_NAME = "protocol";
|
||||||
public static final String SERIAL_NUMBER_PROPERTY_NAME = "serialNumber";
|
public static final String SERIAL_NUMBER_PROPERTY_NAME = "serialNumber";
|
||||||
|
public static final String EXTENDED_DEVICE_STATE_PROPERTY_NAME = "extendedDeviceState";
|
||||||
|
|
||||||
|
// Shared Channel ID's
|
||||||
|
public static final String POWER_CONSUMPTION_CHANNEL_ID = "powerConsumption";
|
||||||
|
public static final String WATER_CONSUMPTION_CHANNEL_ID = "waterConsumption";
|
||||||
|
|
||||||
// List of all Thing Type UIDs
|
// List of all Thing Type UIDs
|
||||||
public static final ThingTypeUID THING_TYPE_XGW3000 = new ThingTypeUID(BINDING_ID, "xgw3000");
|
public static final ThingTypeUID THING_TYPE_XGW3000 = new ThingTypeUID(BINDING_ID, "xgw3000");
|
||||||
|
|
|
@ -23,6 +23,7 @@ import org.openhab.core.types.Type;
|
||||||
* returned by the appliance to a compatible State
|
* returned by the appliance to a compatible State
|
||||||
*
|
*
|
||||||
* @author Karel Goderis - Initial contribution
|
* @author Karel Goderis - Initial contribution
|
||||||
|
* @author Jacob Laursen - Added power/water consumption channels
|
||||||
*/
|
*/
|
||||||
public interface ApplianceChannelSelector {
|
public interface ApplianceChannelSelector {
|
||||||
|
|
||||||
|
@ -45,6 +46,12 @@ public interface ApplianceChannelSelector {
|
||||||
*/
|
*/
|
||||||
boolean isProperty();
|
boolean isProperty();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the given channel is extracted from extended
|
||||||
|
* state information
|
||||||
|
*/
|
||||||
|
boolean isExtendedState();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Returns a State for the given string, taking into
|
* Returns a State for the given string, taking into
|
||||||
|
|
|
@ -99,6 +99,11 @@ public enum CoffeeMachineChannelSelector implements ApplianceChannelSelector {
|
||||||
return isProperty;
|
return isProperty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isExtendedState() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public State getState(String s, DeviceMetaData dmd) {
|
public State getState(String s, DeviceMetaData dmd) {
|
||||||
if (dmd != null) {
|
if (dmd != null) {
|
||||||
|
|
|
@ -13,10 +13,16 @@
|
||||||
package org.openhab.binding.miele.internal.handler;
|
package org.openhab.binding.miele.internal.handler;
|
||||||
|
|
||||||
import static org.openhab.binding.miele.internal.MieleBindingConstants.APPLIANCE_ID;
|
import static org.openhab.binding.miele.internal.MieleBindingConstants.APPLIANCE_ID;
|
||||||
|
import static org.openhab.binding.miele.internal.MieleBindingConstants.POWER_CONSUMPTION_CHANNEL_ID;
|
||||||
import static org.openhab.binding.miele.internal.MieleBindingConstants.PROTOCOL_PROPERTY_NAME;
|
import static org.openhab.binding.miele.internal.MieleBindingConstants.PROTOCOL_PROPERTY_NAME;
|
||||||
|
import static org.openhab.binding.miele.internal.MieleBindingConstants.WATER_CONSUMPTION_CHANNEL_ID;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
import org.openhab.binding.miele.internal.FullyQualifiedApplianceIdentifier;
|
import org.openhab.binding.miele.internal.FullyQualifiedApplianceIdentifier;
|
||||||
import org.openhab.core.library.types.OnOffType;
|
import org.openhab.core.library.types.OnOffType;
|
||||||
|
import org.openhab.core.library.types.QuantityType;
|
||||||
|
import org.openhab.core.library.unit.Units;
|
||||||
import org.openhab.core.thing.ChannelUID;
|
import org.openhab.core.thing.ChannelUID;
|
||||||
import org.openhab.core.thing.Thing;
|
import org.openhab.core.thing.Thing;
|
||||||
import org.openhab.core.types.Command;
|
import org.openhab.core.types.Command;
|
||||||
|
@ -33,9 +39,14 @@ import com.google.gson.JsonElement;
|
||||||
* @author Karel Goderis - Initial contribution
|
* @author Karel Goderis - Initial contribution
|
||||||
* @author Kai Kreuzer - fixed handling of REFRESH commands
|
* @author Kai Kreuzer - fixed handling of REFRESH commands
|
||||||
* @author Martin Lepsy - fixed handling of empty JSON results
|
* @author Martin Lepsy - fixed handling of empty JSON results
|
||||||
* @author Jacob Laursen - Fixed multicast and protocol support (ZigBee/LAN)
|
* @author Jacob Laursen - Fixed multicast and protocol support (ZigBee/LAN), added power/water consumption channels
|
||||||
*/
|
*/
|
||||||
public class DishWasherHandler extends MieleApplianceHandler<DishwasherChannelSelector> {
|
public class DishWasherHandler extends MieleApplianceHandler<DishwasherChannelSelector>
|
||||||
|
implements ExtendedDeviceStateListener {
|
||||||
|
|
||||||
|
private static final int POWER_CONSUMPTION_BYTE_POSITION = 16;
|
||||||
|
private static final int WATER_CONSUMPTION_BYTE_POSITION = 18;
|
||||||
|
private static final int EXTENDED_STATE_SIZE_BYTES = 24;
|
||||||
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(DishWasherHandler.class);
|
private final Logger logger = LoggerFactory.getLogger(DishWasherHandler.class);
|
||||||
|
|
||||||
|
@ -84,4 +95,20 @@ public class DishWasherHandler extends MieleApplianceHandler<DishwasherChannelSe
|
||||||
channelID, command.toString());
|
channelID, command.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onApplianceExtendedStateChanged(byte[] extendedDeviceState) {
|
||||||
|
if (extendedDeviceState.length != EXTENDED_STATE_SIZE_BYTES) {
|
||||||
|
logger.error("Unexpected size of extended state: {}", extendedDeviceState);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigDecimal kiloWattHoursTenths = BigDecimal
|
||||||
|
.valueOf(extendedDeviceState[POWER_CONSUMPTION_BYTE_POSITION] & 0xff);
|
||||||
|
var kiloWattHours = new QuantityType<>(kiloWattHoursTenths.divide(BigDecimal.valueOf(10)), Units.KILOWATT_HOUR);
|
||||||
|
updateExtendedState(POWER_CONSUMPTION_CHANNEL_ID, kiloWattHours);
|
||||||
|
|
||||||
|
BigDecimal decilitres = BigDecimal.valueOf(extendedDeviceState[WATER_CONSUMPTION_BYTE_POSITION] & 0xff);
|
||||||
|
var litres = new QuantityType<>(decilitres.divide(BigDecimal.valueOf(10)), Units.LITRE);
|
||||||
|
updateExtendedState(WATER_CONSUMPTION_CHANNEL_ID, litres);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,10 @@
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.miele.internal.handler;
|
package org.openhab.binding.miele.internal.handler;
|
||||||
|
|
||||||
|
import static org.openhab.binding.miele.internal.MieleBindingConstants.EXTENDED_DEVICE_STATE_PROPERTY_NAME;
|
||||||
|
import static org.openhab.binding.miele.internal.MieleBindingConstants.POWER_CONSUMPTION_CHANNEL_ID;
|
||||||
|
import static org.openhab.binding.miele.internal.MieleBindingConstants.WATER_CONSUMPTION_CHANNEL_ID;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
@ -22,6 +26,7 @@ import org.openhab.binding.miele.internal.handler.MieleBridgeHandler.DeviceMetaD
|
||||||
import org.openhab.core.library.types.DateTimeType;
|
import org.openhab.core.library.types.DateTimeType;
|
||||||
import org.openhab.core.library.types.OnOffType;
|
import org.openhab.core.library.types.OnOffType;
|
||||||
import org.openhab.core.library.types.OpenClosedType;
|
import org.openhab.core.library.types.OpenClosedType;
|
||||||
|
import org.openhab.core.library.types.QuantityType;
|
||||||
import org.openhab.core.library.types.StringType;
|
import org.openhab.core.library.types.StringType;
|
||||||
import org.openhab.core.types.State;
|
import org.openhab.core.types.State;
|
||||||
import org.openhab.core.types.Type;
|
import org.openhab.core.types.Type;
|
||||||
|
@ -36,17 +41,18 @@ import com.google.gson.JsonElement;
|
||||||
*
|
*
|
||||||
* @author Karel Goderis - Initial contribution
|
* @author Karel Goderis - Initial contribution
|
||||||
* @author Kai Kreuzer - Changed START_TIME to DateTimeType
|
* @author Kai Kreuzer - Changed START_TIME to DateTimeType
|
||||||
|
* @author Jacob Laursen - Added power/water consumption channels
|
||||||
*/
|
*/
|
||||||
public enum DishwasherChannelSelector implements ApplianceChannelSelector {
|
public enum DishwasherChannelSelector implements ApplianceChannelSelector {
|
||||||
|
|
||||||
PRODUCT_TYPE("productTypeId", "productType", StringType.class, true),
|
PRODUCT_TYPE("productTypeId", "productType", StringType.class, true, false),
|
||||||
DEVICE_TYPE("mieleDeviceType", "deviceType", StringType.class, true),
|
DEVICE_TYPE("mieleDeviceType", "deviceType", StringType.class, true, false),
|
||||||
BRAND_ID("brandId", "brandId", StringType.class, true),
|
BRAND_ID("brandId", "brandId", StringType.class, true, false),
|
||||||
COMPANY_ID("companyId", "companyId", StringType.class, true),
|
COMPANY_ID("companyId", "companyId", StringType.class, true, false),
|
||||||
STATE("state", "state", StringType.class, false),
|
STATE("state", "state", StringType.class, false, false),
|
||||||
PROGRAMID("programId", "program", StringType.class, false),
|
PROGRAMID("programId", "program", StringType.class, false, false),
|
||||||
PROGRAMPHASE("phase", "phase", StringType.class, false),
|
PROGRAMPHASE("phase", "phase", StringType.class, false, false),
|
||||||
START_TIME("startTime", "start", DateTimeType.class, false) {
|
START_TIME("startTime", "start", DateTimeType.class, false, false) {
|
||||||
@Override
|
@Override
|
||||||
public State getState(String s, DeviceMetaData dmd) {
|
public State getState(String s, DeviceMetaData dmd) {
|
||||||
Date date = new Date();
|
Date date = new Date();
|
||||||
|
@ -60,7 +66,7 @@ public enum DishwasherChannelSelector implements ApplianceChannelSelector {
|
||||||
return getState(dateFormatter.format(date));
|
return getState(dateFormatter.format(date));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
DURATION("duration", "duration", DateTimeType.class, false) {
|
DURATION("duration", "duration", DateTimeType.class, false, false) {
|
||||||
@Override
|
@Override
|
||||||
public State getState(String s, DeviceMetaData dmd) {
|
public State getState(String s, DeviceMetaData dmd) {
|
||||||
Date date = new Date();
|
Date date = new Date();
|
||||||
|
@ -74,7 +80,7 @@ public enum DishwasherChannelSelector implements ApplianceChannelSelector {
|
||||||
return getState(dateFormatter.format(date));
|
return getState(dateFormatter.format(date));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ELAPSED_TIME("elapsedTime", "elapsed", DateTimeType.class, false) {
|
ELAPSED_TIME("elapsedTime", "elapsed", DateTimeType.class, false, false) {
|
||||||
@Override
|
@Override
|
||||||
public State getState(String s, DeviceMetaData dmd) {
|
public State getState(String s, DeviceMetaData dmd) {
|
||||||
Date date = new Date();
|
Date date = new Date();
|
||||||
|
@ -88,7 +94,7 @@ public enum DishwasherChannelSelector implements ApplianceChannelSelector {
|
||||||
return getState(dateFormatter.format(date));
|
return getState(dateFormatter.format(date));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
FINISH_TIME("finishTime", "finish", DateTimeType.class, false) {
|
FINISH_TIME("finishTime", "finish", DateTimeType.class, false, false) {
|
||||||
@Override
|
@Override
|
||||||
public State getState(String s, DeviceMetaData dmd) {
|
public State getState(String s, DeviceMetaData dmd) {
|
||||||
Date date = new Date();
|
Date date = new Date();
|
||||||
|
@ -102,7 +108,7 @@ public enum DishwasherChannelSelector implements ApplianceChannelSelector {
|
||||||
return getState(dateFormatter.format(date));
|
return getState(dateFormatter.format(date));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
DOOR("signalDoor", "door", OpenClosedType.class, false) {
|
DOOR("signalDoor", "door", OpenClosedType.class, false, false) {
|
||||||
@Override
|
@Override
|
||||||
public State getState(String s, DeviceMetaData dmd) {
|
public State getState(String s, DeviceMetaData dmd) {
|
||||||
if ("true".equals(s)) {
|
if ("true".equals(s)) {
|
||||||
|
@ -116,7 +122,11 @@ public enum DishwasherChannelSelector implements ApplianceChannelSelector {
|
||||||
return UnDefType.UNDEF;
|
return UnDefType.UNDEF;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
SWITCH(null, "switch", OnOffType.class, false);
|
SWITCH(null, "switch", OnOffType.class, false, false),
|
||||||
|
POWER_CONSUMPTION(EXTENDED_DEVICE_STATE_PROPERTY_NAME, POWER_CONSUMPTION_CHANNEL_ID, QuantityType.class, false,
|
||||||
|
true),
|
||||||
|
WATER_CONSUMPTION(EXTENDED_DEVICE_STATE_PROPERTY_NAME, WATER_CONSUMPTION_CHANNEL_ID, QuantityType.class, false,
|
||||||
|
true);
|
||||||
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(DishwasherChannelSelector.class);
|
private final Logger logger = LoggerFactory.getLogger(DishwasherChannelSelector.class);
|
||||||
|
|
||||||
|
@ -124,13 +134,15 @@ public enum DishwasherChannelSelector implements ApplianceChannelSelector {
|
||||||
private final String channelID;
|
private final String channelID;
|
||||||
private final Class<? extends Type> typeClass;
|
private final Class<? extends Type> typeClass;
|
||||||
private final boolean isProperty;
|
private final boolean isProperty;
|
||||||
|
private final boolean isExtendedState;
|
||||||
|
|
||||||
DishwasherChannelSelector(String propertyID, String channelID, Class<? extends Type> typeClass,
|
DishwasherChannelSelector(String propertyID, String channelID, Class<? extends Type> typeClass, boolean isProperty,
|
||||||
boolean isProperty) {
|
boolean isExtendedState) {
|
||||||
this.mieleID = propertyID;
|
this.mieleID = propertyID;
|
||||||
this.channelID = channelID;
|
this.channelID = channelID;
|
||||||
this.typeClass = typeClass;
|
this.typeClass = typeClass;
|
||||||
this.isProperty = isProperty;
|
this.isProperty = isProperty;
|
||||||
|
this.isExtendedState = isExtendedState;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -158,6 +170,11 @@ public enum DishwasherChannelSelector implements ApplianceChannelSelector {
|
||||||
return isProperty;
|
return isProperty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isExtendedState() {
|
||||||
|
return isExtendedState;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public State getState(String s, DeviceMetaData dmd) {
|
public State getState(String s, DeviceMetaData dmd) {
|
||||||
if (dmd != null) {
|
if (dmd != null) {
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
/**
|
||||||
|
* 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.miele.internal.handler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appliance handlers can implement the {@link ExtendedDeviceStateListener} interface
|
||||||
|
* to extract additional information from the ExtendedDeviceState property.
|
||||||
|
*
|
||||||
|
* @author Jacob Laursen - Added power/water consumption channels
|
||||||
|
*/
|
||||||
|
public interface ExtendedDeviceStateListener {
|
||||||
|
void onApplianceExtendedStateChanged(byte[] extendedDeviceState);
|
||||||
|
}
|
|
@ -109,6 +109,11 @@ public enum FridgeChannelSelector implements ApplianceChannelSelector {
|
||||||
return isProperty;
|
return isProperty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isExtendedState() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public State getState(String s, DeviceMetaData dmd) {
|
public State getState(String s, DeviceMetaData dmd) {
|
||||||
if (dmd != null) {
|
if (dmd != null) {
|
||||||
|
|
|
@ -126,6 +126,11 @@ public enum FridgeFreezerChannelSelector implements ApplianceChannelSelector {
|
||||||
return isProperty;
|
return isProperty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isExtendedState() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public State getState(String s, DeviceMetaData dmd) {
|
public State getState(String s, DeviceMetaData dmd) {
|
||||||
if (dmd != null) {
|
if (dmd != null) {
|
||||||
|
|
|
@ -129,6 +129,11 @@ public enum HobChannelSelector implements ApplianceChannelSelector {
|
||||||
return isProperty;
|
return isProperty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isExtendedState() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public State getState(String s, DeviceMetaData dmd) {
|
public State getState(String s, DeviceMetaData dmd) {
|
||||||
if (dmd != null) {
|
if (dmd != null) {
|
||||||
|
|
|
@ -96,6 +96,11 @@ public enum HoodChannelSelector implements ApplianceChannelSelector {
|
||||||
return isProperty;
|
return isProperty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isExtendedState() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public State getState(String s, DeviceMetaData dmd) {
|
public State getState(String s, DeviceMetaData dmd) {
|
||||||
if (dmd != null) {
|
if (dmd != null) {
|
||||||
|
|
|
@ -21,6 +21,7 @@ import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.openhab.binding.miele.internal.ExtendedDeviceStateUtil;
|
||||||
import org.openhab.binding.miele.internal.FullyQualifiedApplianceIdentifier;
|
import org.openhab.binding.miele.internal.FullyQualifiedApplianceIdentifier;
|
||||||
import org.openhab.binding.miele.internal.handler.MieleBridgeHandler.DeviceClassObject;
|
import org.openhab.binding.miele.internal.handler.MieleBridgeHandler.DeviceClassObject;
|
||||||
import org.openhab.binding.miele.internal.handler.MieleBridgeHandler.DeviceMetaData;
|
import org.openhab.binding.miele.internal.handler.MieleBridgeHandler.DeviceMetaData;
|
||||||
|
@ -36,6 +37,7 @@ import org.openhab.core.thing.binding.BaseThingHandler;
|
||||||
import org.openhab.core.thing.binding.ThingHandler;
|
import org.openhab.core.thing.binding.ThingHandler;
|
||||||
import org.openhab.core.types.Command;
|
import org.openhab.core.types.Command;
|
||||||
import org.openhab.core.types.RefreshType;
|
import org.openhab.core.types.RefreshType;
|
||||||
|
import org.openhab.core.types.State;
|
||||||
import org.openhab.core.types.UnDefType;
|
import org.openhab.core.types.UnDefType;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -155,8 +157,10 @@ public abstract class MieleApplianceHandler<E extends Enum<E> & ApplianceChannel
|
||||||
for (JsonElement prop : dco.Properties.getAsJsonArray()) {
|
for (JsonElement prop : dco.Properties.getAsJsonArray()) {
|
||||||
try {
|
try {
|
||||||
DeviceProperty dp = gson.fromJson(prop, DeviceProperty.class);
|
DeviceProperty dp = gson.fromJson(prop, DeviceProperty.class);
|
||||||
dp.Value = StringUtils.trim(dp.Value);
|
if (!dp.Name.equals(EXTENDED_DEVICE_STATE_PROPERTY_NAME)) {
|
||||||
dp.Value = StringUtils.strip(dp.Value);
|
dp.Value = StringUtils.trim(dp.Value);
|
||||||
|
dp.Value = StringUtils.strip(dp.Value);
|
||||||
|
}
|
||||||
|
|
||||||
onAppliancePropertyChanged(applicationIdentifier, dp);
|
onAppliancePropertyChanged(applicationIdentifier, dp);
|
||||||
} catch (Exception p) {
|
} catch (Exception p) {
|
||||||
|
@ -211,6 +215,18 @@ public abstract class MieleApplianceHandler<E extends Enum<E> & ApplianceChannel
|
||||||
metaDataCache.put(new StringBuilder().append(dp.Name).toString().trim(), metadata);
|
metaDataCache.put(new StringBuilder().append(dp.Name).toString().trim(), metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dp.Name.equals(EXTENDED_DEVICE_STATE_PROPERTY_NAME)) {
|
||||||
|
if (!dp.Value.isEmpty()) {
|
||||||
|
byte[] extendedStateBytes = ExtendedDeviceStateUtil.stringToBytes(dp.Value);
|
||||||
|
logger.trace("Extended device state for {}: {}", getThing().getUID(),
|
||||||
|
ExtendedDeviceStateUtil.bytesToHex(extendedStateBytes));
|
||||||
|
if (this instanceof ExtendedDeviceStateListener) {
|
||||||
|
((ExtendedDeviceStateListener) this).onApplianceExtendedStateChanged(extendedStateBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ApplianceChannelSelector selector = null;
|
ApplianceChannelSelector selector = null;
|
||||||
try {
|
try {
|
||||||
selector = getValueSelectorFromMieleID(dp.Name);
|
selector = getValueSelectorFromMieleID(dp.Name);
|
||||||
|
@ -244,6 +260,12 @@ public abstract class MieleApplianceHandler<E extends Enum<E> & ApplianceChannel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void updateExtendedState(String channelId, State state) {
|
||||||
|
ChannelUID channelUid = new ChannelUID(getThing().getUID(), channelId);
|
||||||
|
logger.trace("Update state of {} with extended state '{}'", channelUid, state);
|
||||||
|
updateState(channelUid, state);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onApplianceRemoved(HomeDevice appliance) {
|
public void onApplianceRemoved(HomeDevice appliance) {
|
||||||
if (applianceId == null) {
|
if (applianceId == null) {
|
||||||
|
|
|
@ -185,6 +185,11 @@ public enum OvenChannelSelector implements ApplianceChannelSelector {
|
||||||
return isProperty;
|
return isProperty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isExtendedState() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public State getState(String s, DeviceMetaData dmd) {
|
public State getState(String s, DeviceMetaData dmd) {
|
||||||
if (dmd != null) {
|
if (dmd != null) {
|
||||||
|
|
|
@ -167,6 +167,11 @@ public enum TumbleDryerChannelSelector implements ApplianceChannelSelector {
|
||||||
return isProperty;
|
return isProperty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isExtendedState() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public State getState(String s, DeviceMetaData dmd) {
|
public State getState(String s, DeviceMetaData dmd) {
|
||||||
if (dmd != null) {
|
if (dmd != null) {
|
||||||
|
|
|
@ -12,6 +12,10 @@
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.miele.internal.handler;
|
package org.openhab.binding.miele.internal.handler;
|
||||||
|
|
||||||
|
import static org.openhab.binding.miele.internal.MieleBindingConstants.EXTENDED_DEVICE_STATE_PROPERTY_NAME;
|
||||||
|
import static org.openhab.binding.miele.internal.MieleBindingConstants.POWER_CONSUMPTION_CHANNEL_ID;
|
||||||
|
import static org.openhab.binding.miele.internal.MieleBindingConstants.WATER_CONSUMPTION_CHANNEL_ID;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
@ -24,6 +28,7 @@ import org.openhab.core.library.types.DateTimeType;
|
||||||
import org.openhab.core.library.types.DecimalType;
|
import org.openhab.core.library.types.DecimalType;
|
||||||
import org.openhab.core.library.types.OnOffType;
|
import org.openhab.core.library.types.OnOffType;
|
||||||
import org.openhab.core.library.types.OpenClosedType;
|
import org.openhab.core.library.types.OpenClosedType;
|
||||||
|
import org.openhab.core.library.types.QuantityType;
|
||||||
import org.openhab.core.library.types.StringType;
|
import org.openhab.core.library.types.StringType;
|
||||||
import org.openhab.core.types.State;
|
import org.openhab.core.types.State;
|
||||||
import org.openhab.core.types.Type;
|
import org.openhab.core.types.Type;
|
||||||
|
@ -38,18 +43,19 @@ import com.google.gson.JsonElement;
|
||||||
*
|
*
|
||||||
* @author Karel Goderis - Initial contribution
|
* @author Karel Goderis - Initial contribution
|
||||||
* @author Kai Kreuzer - Changed START_TIME to DateTimeType
|
* @author Kai Kreuzer - Changed START_TIME to DateTimeType
|
||||||
|
* @author Jacob Laursen - Added power/water consumption channels
|
||||||
*/
|
*/
|
||||||
public enum WashingMachineChannelSelector implements ApplianceChannelSelector {
|
public enum WashingMachineChannelSelector implements ApplianceChannelSelector {
|
||||||
|
|
||||||
PRODUCT_TYPE("productTypeId", "productType", StringType.class, true),
|
PRODUCT_TYPE("productTypeId", "productType", StringType.class, true, false),
|
||||||
DEVICE_TYPE("mieleDeviceType", "deviceType", StringType.class, true),
|
DEVICE_TYPE("mieleDeviceType", "deviceType", StringType.class, true, false),
|
||||||
BRAND_ID("brandId", "brandId", StringType.class, true),
|
BRAND_ID("brandId", "brandId", StringType.class, true, false),
|
||||||
COMPANY_ID("companyId", "companyId", StringType.class, true),
|
COMPANY_ID("companyId", "companyId", StringType.class, true, false),
|
||||||
STATE("state", "state", StringType.class, false),
|
STATE("state", "state", StringType.class, false, false),
|
||||||
PROGRAMID("programId", "program", StringType.class, false),
|
PROGRAMID("programId", "program", StringType.class, false, false),
|
||||||
PROGRAMTYPE("programType", "type", StringType.class, false),
|
PROGRAMTYPE("programType", "type", StringType.class, false, false),
|
||||||
PROGRAMPHASE("phase", "phase", StringType.class, false),
|
PROGRAMPHASE("phase", "phase", StringType.class, false, false),
|
||||||
START_TIME("startTime", "start", DateTimeType.class, false) {
|
START_TIME("startTime", "start", DateTimeType.class, false, false) {
|
||||||
@Override
|
@Override
|
||||||
public State getState(String s, DeviceMetaData dmd) {
|
public State getState(String s, DeviceMetaData dmd) {
|
||||||
Date date = new Date();
|
Date date = new Date();
|
||||||
|
@ -63,7 +69,7 @@ public enum WashingMachineChannelSelector implements ApplianceChannelSelector {
|
||||||
return getState(dateFormatter.format(date));
|
return getState(dateFormatter.format(date));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
DURATION("duration", "duration", DateTimeType.class, false) {
|
DURATION("duration", "duration", DateTimeType.class, false, false) {
|
||||||
@Override
|
@Override
|
||||||
public State getState(String s, DeviceMetaData dmd) {
|
public State getState(String s, DeviceMetaData dmd) {
|
||||||
Date date = new Date();
|
Date date = new Date();
|
||||||
|
@ -77,7 +83,7 @@ public enum WashingMachineChannelSelector implements ApplianceChannelSelector {
|
||||||
return getState(dateFormatter.format(date));
|
return getState(dateFormatter.format(date));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ELAPSED_TIME("elapsedTime", "elapsed", DateTimeType.class, false) {
|
ELAPSED_TIME("elapsedTime", "elapsed", DateTimeType.class, false, false) {
|
||||||
@Override
|
@Override
|
||||||
public State getState(String s, DeviceMetaData dmd) {
|
public State getState(String s, DeviceMetaData dmd) {
|
||||||
Date date = new Date();
|
Date date = new Date();
|
||||||
|
@ -91,7 +97,7 @@ public enum WashingMachineChannelSelector implements ApplianceChannelSelector {
|
||||||
return getState(dateFormatter.format(date));
|
return getState(dateFormatter.format(date));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
FINISH_TIME("finishTime", "finish", DateTimeType.class, false) {
|
FINISH_TIME("finishTime", "finish", DateTimeType.class, false, false) {
|
||||||
@Override
|
@Override
|
||||||
public State getState(String s, DeviceMetaData dmd) {
|
public State getState(String s, DeviceMetaData dmd) {
|
||||||
Date date = new Date();
|
Date date = new Date();
|
||||||
|
@ -105,13 +111,13 @@ public enum WashingMachineChannelSelector implements ApplianceChannelSelector {
|
||||||
return getState(dateFormatter.format(date));
|
return getState(dateFormatter.format(date));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
TARGET_TEMP("targetTemperature", "target", DecimalType.class, false) {
|
TARGET_TEMP("targetTemperature", "target", DecimalType.class, false, false) {
|
||||||
@Override
|
@Override
|
||||||
public State getState(String s, DeviceMetaData dmd) {
|
public State getState(String s, DeviceMetaData dmd) {
|
||||||
return getState(s);
|
return getState(s);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
SPINNING_SPEED("spinningSpeed", "spinningspeed", StringType.class, false) {
|
SPINNING_SPEED("spinningSpeed", "spinningspeed", StringType.class, false, false) {
|
||||||
@Override
|
@Override
|
||||||
public State getState(String s, DeviceMetaData dmd) {
|
public State getState(String s, DeviceMetaData dmd) {
|
||||||
if ("0".equals(s)) {
|
if ("0".equals(s)) {
|
||||||
|
@ -123,7 +129,7 @@ public enum WashingMachineChannelSelector implements ApplianceChannelSelector {
|
||||||
return getState(Integer.toString((Integer.valueOf(s) * 10)));
|
return getState(Integer.toString((Integer.valueOf(s) * 10)));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
DOOR("signalDoor", "door", OpenClosedType.class, false) {
|
DOOR("signalDoor", "door", OpenClosedType.class, false, false) {
|
||||||
@Override
|
@Override
|
||||||
|
|
||||||
public State getState(String s, DeviceMetaData dmd) {
|
public State getState(String s, DeviceMetaData dmd) {
|
||||||
|
@ -138,7 +144,11 @@ public enum WashingMachineChannelSelector implements ApplianceChannelSelector {
|
||||||
return UnDefType.UNDEF;
|
return UnDefType.UNDEF;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
SWITCH(null, "switch", OnOffType.class, false);
|
SWITCH(null, "switch", OnOffType.class, false, false),
|
||||||
|
POWER_CONSUMPTION(EXTENDED_DEVICE_STATE_PROPERTY_NAME, POWER_CONSUMPTION_CHANNEL_ID, QuantityType.class, false,
|
||||||
|
true),
|
||||||
|
WATER_CONSUMPTION(EXTENDED_DEVICE_STATE_PROPERTY_NAME, WATER_CONSUMPTION_CHANNEL_ID, QuantityType.class, false,
|
||||||
|
true);
|
||||||
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(WashingMachineChannelSelector.class);
|
private final Logger logger = LoggerFactory.getLogger(WashingMachineChannelSelector.class);
|
||||||
|
|
||||||
|
@ -146,13 +156,15 @@ public enum WashingMachineChannelSelector implements ApplianceChannelSelector {
|
||||||
private final String channelID;
|
private final String channelID;
|
||||||
private final Class<? extends Type> typeClass;
|
private final Class<? extends Type> typeClass;
|
||||||
private final boolean isProperty;
|
private final boolean isProperty;
|
||||||
|
private final boolean isExtendedState;
|
||||||
|
|
||||||
WashingMachineChannelSelector(String propertyID, String channelID, Class<? extends Type> typeClass,
|
WashingMachineChannelSelector(String propertyID, String channelID, Class<? extends Type> typeClass,
|
||||||
boolean isProperty) {
|
boolean isProperty, boolean isExtendedState) {
|
||||||
this.mieleID = propertyID;
|
this.mieleID = propertyID;
|
||||||
this.channelID = channelID;
|
this.channelID = channelID;
|
||||||
this.typeClass = typeClass;
|
this.typeClass = typeClass;
|
||||||
this.isProperty = isProperty;
|
this.isProperty = isProperty;
|
||||||
|
this.isExtendedState = isExtendedState;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -180,6 +192,11 @@ public enum WashingMachineChannelSelector implements ApplianceChannelSelector {
|
||||||
return isProperty;
|
return isProperty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isExtendedState() {
|
||||||
|
return isExtendedState;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public State getState(String s, DeviceMetaData dmd) {
|
public State getState(String s, DeviceMetaData dmd) {
|
||||||
if (dmd != null) {
|
if (dmd != null) {
|
||||||
|
|
|
@ -13,10 +13,16 @@
|
||||||
package org.openhab.binding.miele.internal.handler;
|
package org.openhab.binding.miele.internal.handler;
|
||||||
|
|
||||||
import static org.openhab.binding.miele.internal.MieleBindingConstants.APPLIANCE_ID;
|
import static org.openhab.binding.miele.internal.MieleBindingConstants.APPLIANCE_ID;
|
||||||
|
import static org.openhab.binding.miele.internal.MieleBindingConstants.POWER_CONSUMPTION_CHANNEL_ID;
|
||||||
import static org.openhab.binding.miele.internal.MieleBindingConstants.PROTOCOL_PROPERTY_NAME;
|
import static org.openhab.binding.miele.internal.MieleBindingConstants.PROTOCOL_PROPERTY_NAME;
|
||||||
|
import static org.openhab.binding.miele.internal.MieleBindingConstants.WATER_CONSUMPTION_CHANNEL_ID;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
import org.openhab.binding.miele.internal.FullyQualifiedApplianceIdentifier;
|
import org.openhab.binding.miele.internal.FullyQualifiedApplianceIdentifier;
|
||||||
import org.openhab.core.library.types.OnOffType;
|
import org.openhab.core.library.types.OnOffType;
|
||||||
|
import org.openhab.core.library.types.QuantityType;
|
||||||
|
import org.openhab.core.library.unit.Units;
|
||||||
import org.openhab.core.thing.ChannelUID;
|
import org.openhab.core.thing.ChannelUID;
|
||||||
import org.openhab.core.thing.Thing;
|
import org.openhab.core.thing.Thing;
|
||||||
import org.openhab.core.types.Command;
|
import org.openhab.core.types.Command;
|
||||||
|
@ -33,9 +39,14 @@ import com.google.gson.JsonElement;
|
||||||
* @author Karel Goderis - Initial contribution
|
* @author Karel Goderis - Initial contribution
|
||||||
* @author Kai Kreuzer - fixed handling of REFRESH commands
|
* @author Kai Kreuzer - fixed handling of REFRESH commands
|
||||||
* @author Martin Lepsy - fixed handling of empty JSON results
|
* @author Martin Lepsy - fixed handling of empty JSON results
|
||||||
* @author Jacob Laursen - Fixed multicast and protocol support (ZigBee/LAN)
|
* @author Jacob Laursen - Fixed multicast and protocol support (ZigBee/LAN), added power/water consumption channels
|
||||||
**/
|
**/
|
||||||
public class WashingMachineHandler extends MieleApplianceHandler<WashingMachineChannelSelector> {
|
public class WashingMachineHandler extends MieleApplianceHandler<WashingMachineChannelSelector>
|
||||||
|
implements ExtendedDeviceStateListener {
|
||||||
|
|
||||||
|
private static final int POWER_CONSUMPTION_BYTE_POSITION = 51;
|
||||||
|
private static final int WATER_CONSUMPTION_BYTE_POSITION = 53;
|
||||||
|
private static final int EXTENDED_STATE_SIZE_BYTES = 59;
|
||||||
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(WashingMachineHandler.class);
|
private final Logger logger = LoggerFactory.getLogger(WashingMachineHandler.class);
|
||||||
|
|
||||||
|
@ -85,4 +96,20 @@ public class WashingMachineHandler extends MieleApplianceHandler<WashingMachineC
|
||||||
channelID, command.toString());
|
channelID, command.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onApplianceExtendedStateChanged(byte[] extendedDeviceState) {
|
||||||
|
if (extendedDeviceState.length != EXTENDED_STATE_SIZE_BYTES) {
|
||||||
|
logger.error("Unexpected size of extended state: {}", extendedDeviceState);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigDecimal kiloWattHoursTenths = BigDecimal
|
||||||
|
.valueOf(extendedDeviceState[POWER_CONSUMPTION_BYTE_POSITION] & 0xff);
|
||||||
|
var kiloWattHours = new QuantityType<>(kiloWattHoursTenths.divide(BigDecimal.valueOf(10)), Units.KILOWATT_HOUR);
|
||||||
|
updateExtendedState(POWER_CONSUMPTION_CHANNEL_ID, kiloWattHours);
|
||||||
|
|
||||||
|
var litres = new QuantityType<>(BigDecimal.valueOf(extendedDeviceState[WATER_CONSUMPTION_BYTE_POSITION] & 0xff),
|
||||||
|
Units.LITRE);
|
||||||
|
updateExtendedState(WATER_CONSUMPTION_CHANNEL_ID, litres);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -212,4 +212,18 @@
|
||||||
<state readOnly="true"></state>
|
<state readOnly="true"></state>
|
||||||
</channel-type>
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="powerConsumption" advanced="false">
|
||||||
|
<item-type>Number:Power</item-type>
|
||||||
|
<label>Power Consumption</label>
|
||||||
|
<description>Power consumption by the currently running program on the appliance</description>
|
||||||
|
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="waterConsumption" advanced="false">
|
||||||
|
<item-type>Number:Volume</item-type>
|
||||||
|
<label>Water Consumption</label>
|
||||||
|
<description>Water consumption by the currently running program on the appliance</description>
|
||||||
|
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
</thing:thing-descriptions>
|
</thing:thing-descriptions>
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
<channel id="finish" typeId="finish"/>
|
<channel id="finish" typeId="finish"/>
|
||||||
<channel id="door" typeId="door"/>
|
<channel id="door" typeId="door"/>
|
||||||
<channel id="switch" typeId="switch"/>
|
<channel id="switch" typeId="switch"/>
|
||||||
|
<channel id="powerConsumption" typeId="powerConsumption"/>
|
||||||
|
<channel id="waterConsumption" typeId="waterConsumption"/>
|
||||||
</channels>
|
</channels>
|
||||||
|
|
||||||
<representation-property>uid</representation-property>
|
<representation-property>uid</representation-property>
|
||||||
|
|
|
@ -26,6 +26,8 @@
|
||||||
<channel id="switch" typeId="switch"/>
|
<channel id="switch" typeId="switch"/>
|
||||||
<channel id="target" typeId="target"/>
|
<channel id="target" typeId="target"/>
|
||||||
<channel id="spinningspeed" typeId="spinningspeed"/>
|
<channel id="spinningspeed" typeId="spinningspeed"/>
|
||||||
|
<channel id="powerConsumption" typeId="powerConsumption"/>
|
||||||
|
<channel id="waterConsumption" typeId="waterConsumption"/>
|
||||||
</channels>
|
</channels>
|
||||||
|
|
||||||
<representation-property>uid</representation-property>
|
<representation-property>uid</representation-property>
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
/**
|
||||||
|
* 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.miele.internal;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.openhab.core.test.java.JavaTest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class provides test cases for {@link
|
||||||
|
* org.openhab.binding.miele.internal.ExtendedDeviceStateUtil}
|
||||||
|
*
|
||||||
|
* @author Jacob Laursen - Added power/water consumption channels
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class ExtendedDeviceStateUtilTest extends JavaTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void bytesToHexWhenTopBitIsUsedReturnsCorrectString() {
|
||||||
|
String actual = ExtendedDeviceStateUtil
|
||||||
|
.bytesToHex(new byte[] { (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef });
|
||||||
|
assertEquals("DEADBEEF", actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This test guards that the UTF-16 returned by the RPC-JSON API will be
|
||||||
|
* considered as a sequence of 8-bit characters and converted into bytes
|
||||||
|
* accordingly. Default behaviour of String.getBytes() assumes UTF-8
|
||||||
|
* and adds a 0xc2 byte before any character out of ASCII range.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void stringToBytesWhenTopBitIsUsedReturnsSingleByte() {
|
||||||
|
byte[] expected = new byte[] { (byte) 0x00, (byte) 0x80, (byte) 0x00 };
|
||||||
|
byte[] actual = ExtendedDeviceStateUtil.stringToBytes("\u0000\u0080\u0000");
|
||||||
|
assertArrayEquals(expected, actual);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue