Skip to content

Commit

Permalink
[miele] Localization of state, program and phase (openhab#11603)
Browse files Browse the repository at this point in the history
* Initial changes for state, program and phase localization.
* Fix bridge configuration reload.
* Extracted DeviceMetaData from MieleBridgeHandler.
* Fix fallback to gateway text.
* Consolidate getMieleEnum in DeviceMetaData.
* Localize thing offline texts and increased accuracy.
* Validate language during bridge initialization.
* Interpret magic value for temperature.
* Add missing i18n channel label/description strings.
* Add missing washing machine phase texts in Dutch.
* Add missing French dishwasher phase texts.

Fixes openhab#11602

Signed-off-by: Jacob Laursen <[email protected]>
Signed-off-by: Michael Schmidt <[email protected]>
  • Loading branch information
jlaur authored and mischmidt83 committed Jan 9, 2022
1 parent d26aaae commit 2abba37
Show file tree
Hide file tree
Showing 36 changed files with 1,340 additions and 430 deletions.
21 changes: 11 additions & 10 deletions bundles/org.openhab.binding.miele/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,15 +128,15 @@ Channels available for each appliance type are listed below.

| Program | Description |
|---------|-------------------------------------|
| 26 | Pots & Pans |
| 27 | Clean Machine |
| 28 | Economy |
| 26 | Intensive |
| 27 | Maintenance programme |
| 28 | ECO |
| 30 | Normal |
| 32 | Sensor Wash |
| 34 | Energy Saver |
| 35 | China & Crystal |
| 32 | Automatic |
| 34 | SolarSave |
| 35 | Gentle |
| 36 | Extra Quiet |
| 37 | SaniWash |
| 37 | Hygiene |
| 38 | QuickPowerWash |
| 42 | Tall items |

Expand Down Expand Up @@ -282,6 +282,7 @@ See oven.
| Program | Description |
|---------|-------------------------------------|
| 10 | Automatic Plus |
| 20 | Cottons |
| 23 | Cottons hygiene |
| 30 | Minimum iron |
| 31 | Gentle minimum iron |
Expand Down Expand Up @@ -314,11 +315,11 @@ See oven.
| 513 | 1 | Programme running |
| 514 | 2 | Drying |
| 515 | 3 | Drying Machine iron |
| 516 | 4 | Drying Hand iron (1) |
| 516 | 4 | Drying Hand iron (2) |
| 517 | 5 | Drying Normal |
| 518 | 6 | Drying Normal+ |
| 519 | 7 | Cooling down |
| 520 | 8 | Drying Hand iron (2) |
| 520 | 8 | Drying Hand iron (1) |
| 522 | 10 | Finished |

#### Washing Machine
Expand All @@ -338,7 +339,7 @@ See oven.
| finish | DateTime | Read | Time to finish the program running on the appliance |
| door | Contact | Read | Current state of the door of the appliance |
| switch | Switch | Write | Switch the appliance on or off |
| target | Number:Temperature | Read | Temperature of the selected program |
| target | Number:Temperature | Read | Temperature of the selected program (10 °C = cold) |
| spinningspeed | String | Read | Spinning speed in the program running on the appliance |
| powerConsumption | Number:Power | Read | Power consumption by the currently running program on the appliance |
| waterConsumption | Number:Volume | Read | Water consumption by the currently running program on the appliance |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* 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.util.Map.Entry;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;

/**
* The {@link DeviceMetaData} class represents the Metadata node in the response JSON.
*
* @author Jacob Laursen - Initial contribution
*/
public class DeviceMetaData {
public String Filter;
public String description;
public String LocalizedID;
public String LocalizedValue;
public JsonObject MieleEnum;
public String access;

public String getMieleEnum(String s) {
if (this.MieleEnum == null) {
return null;
}

for (Entry<String, JsonElement> enumEntry : this.MieleEnum.entrySet()) {
if (enumEntry.getValue().getAsString().trim().equals(s.trim())) {
return enumEntry.getKey();
}
}

return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,13 @@
*/
package org.openhab.binding.miele.internal;

import static org.openhab.binding.miele.internal.MieleBindingConstants.*;

import java.nio.charset.StandardCharsets;
import java.util.Map;

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.types.State;
import org.openhab.core.types.UnDefType;
Expand All @@ -28,6 +32,15 @@
public class DeviceUtil {
private static final byte[] HEX_ARRAY = "0123456789ABCDEF".getBytes(StandardCharsets.US_ASCII);
private static final String TEMPERATURE_UNDEFINED = "32768";
private static final String TEMPERATURE_COLD = "-32760";
private static final String TEXT_PREFIX = "miele.";

private static final Map<String, String> states = Map.ofEntries(Map.entry("1", "off"), Map.entry("2", "stand-by"),
Map.entry("3", "programmed"), Map.entry("4", "waiting-to-start"), Map.entry("5", "running"),
Map.entry("6", "paused"), Map.entry("7", "end"), Map.entry("8", "failure"), Map.entry("9", "abort"),
Map.entry("10", "idle"), Map.entry("11", "rinse-hold"), Map.entry("12", "service"),
Map.entry("13", "super-freezing"), Map.entry("14", "super-cooling"), Map.entry("15", "super-heating"),
Map.entry("144", "default"), Map.entry("145", "locked"), Map.entry("255", "not-connected"));

/**
* Convert byte array to hex representation.
Expand Down Expand Up @@ -60,7 +73,59 @@ public static State getTemperatureState(String s) throws NumberFormatException {
if (TEMPERATURE_UNDEFINED.equals(s)) {
return UnDefType.UNDEF;
}
if (TEMPERATURE_COLD.equals(s)) {
return new QuantityType<>(10, SIUnits.CELSIUS);
}
int temperature = Integer.parseInt(s);
return new QuantityType<>(temperature, SIUnits.CELSIUS);
}

/**
* Get state text for provided string taking into consideration {@link DeviceMetaData}
* as well as built-in/translated strings.
*/
public static State getStateTextState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return getTextState(s, dmd, translationProvider, states, MISSING_STATE_TEXT_PREFIX, "");
}

/**
* Get text for provided string taking into consideration {@link DeviceMetaData}
* as well as built-in/translated strings.
*
* @param s Raw string to be processed
* @param dmd {@link DeviceMetaData} possibly containing LocalizedValue and/or enum from gateway
* @param translationProvider {@link MieleTranslationProvider} for localization support
* @param valueMap Map of numeric values with corresponding text keys
* @param propertyPrefix Property prefix appended to text key (including dot)
* @param appliancePrefix Appliance prefix appended to text key (including dot)
* @return Text string as State
*/
public static State getTextState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider,
Map<String, String> valueMap, String propertyPrefix, String appliancePrefix) {
if ("0".equals(s)) {
return UnDefType.UNDEF;
}

String gatewayText = null;
if (dmd != null) {
if (dmd.LocalizedValue != null && !dmd.LocalizedValue.isEmpty()) {
gatewayText = dmd.LocalizedValue;
} else {
gatewayText = dmd.getMieleEnum(s);
}
}

String value = valueMap.get(s);
if (value != null) {
String key = TEXT_PREFIX + propertyPrefix + appliancePrefix + value;
return new StringType(
translationProvider.getText(key, gatewayText != null ? gatewayText : propertyPrefix + s));
}

if (gatewayText != null) {
return new StringType(gatewayText);
}

return new StringType(propertyPrefix + s);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,21 @@ public class MieleBindingConstants {
public static final int STATE_NOT_CONNECTED = 255;

// Miele missing string prefixes
public static final String MISSING_STATE_TEXT_PREFIX = "state.";
public static final String MISSING_PROGRAM_TEXT_PREFIX = "program.";
public static final String MISSING_PHASE_TEXT_PREFIX = "phase.";

// Miele appliance localization text prefixes
public static final String MIELE_COFFEE_MACHINE_TEXT_PREFIX = "coffeemachine.";
public static final String MIELE_DISHWASHER_TEXT_PREFIX = "dishwasher.";
public static final String MIELE_OVEN_TEXT_PREFIX = "oven.";
public static final String MIELE_TUMBLE_DRYER_TEXT_PREFIX = "tumbledryer.";
public static final String MIELE_WASHING_MACHINE_TEXT_PREFIX = "washingmachine.";

// Bridge config properties
public static final String HOST = "ipAddress";
public static final String INTERFACE = "interface";
public static final String USER_NAME = "userName";
public static final String PASSWORD = "password";
public static final String LANGUAGE = "language";
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
import org.openhab.binding.miele.internal.handler.WashingMachineHandler;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.config.discovery.DiscoveryService;
import org.openhab.core.i18n.LocaleProvider;
import org.openhab.core.i18n.TranslationProvider;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
Expand All @@ -43,7 +45,10 @@
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;

/**
* The {@link MieleHandlerFactory} is responsible for creating things and thing
Expand All @@ -59,8 +64,18 @@ public class MieleHandlerFactory extends BaseThingHandlerFactory {
MieleApplianceHandler.SUPPORTED_THING_TYPES.stream())
.collect(Collectors.toSet());

private final TranslationProvider i18nProvider;
private final LocaleProvider localeProvider;

private Map<ThingUID, ServiceRegistration<?>> discoveryServiceRegs = new HashMap<>();

@Activate
public MieleHandlerFactory(final @Reference TranslationProvider i18nProvider,
final @Reference LocaleProvider localeProvider, ComponentContext componentContext) {
this.i18nProvider = i18nProvider;
this.localeProvider = localeProvider;
}

@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
Expand Down Expand Up @@ -89,31 +104,31 @@ protected ThingHandler createHandler(Thing thing) {
return handler;
} else if (MieleApplianceHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) {
if (thing.getThingTypeUID().equals(THING_TYPE_HOOD)) {
return new HoodHandler(thing);
return new HoodHandler(thing, i18nProvider, localeProvider);
}
if (thing.getThingTypeUID().equals(THING_TYPE_FRIDGEFREEZER)) {
return new FridgeFreezerHandler(thing);
return new FridgeFreezerHandler(thing, i18nProvider, localeProvider);
}
if (thing.getThingTypeUID().equals(THING_TYPE_FRIDGE)) {
return new FridgeHandler(thing);
return new FridgeHandler(thing, i18nProvider, localeProvider);
}
if (thing.getThingTypeUID().equals(THING_TYPE_OVEN)) {
return new OvenHandler(thing);
return new OvenHandler(thing, i18nProvider, localeProvider);
}
if (thing.getThingTypeUID().equals(THING_TYPE_HOB)) {
return new HobHandler(thing);
return new HobHandler(thing, i18nProvider, localeProvider);
}
if (thing.getThingTypeUID().equals(THING_TYPE_WASHINGMACHINE)) {
return new WashingMachineHandler(thing);
return new WashingMachineHandler(thing, i18nProvider, localeProvider);
}
if (thing.getThingTypeUID().equals(THING_TYPE_DRYER)) {
return new TumbleDryerHandler(thing);
return new TumbleDryerHandler(thing, i18nProvider, localeProvider);
}
if (thing.getThingTypeUID().equals(THING_TYPE_DISHWASHER)) {
return new DishWasherHandler(thing);
return new DishWasherHandler(thing, i18nProvider, localeProvider);
}
if (thing.getThingTypeUID().equals(THING_TYPE_COFFEEMACHINE)) {
return new CoffeeMachineHandler(thing);
return new CoffeeMachineHandler(thing, i18nProvider, localeProvider);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/**
* 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.util.Locale;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.i18n.LocaleProvider;
import org.openhab.core.i18n.TranslationProvider;
import org.osgi.framework.Bundle;
import org.osgi.framework.FrameworkUtil;

/**
* {@link MieleTranslationProvider} provides i18n message lookup
*
* @author Jacob Laursen - Initial contribution
*/
@NonNullByDefault
public class MieleTranslationProvider {

private final Bundle bundle;
private final TranslationProvider i18nProvider;
private final LocaleProvider localeProvider;
@Nullable
private final Locale locale;

public MieleTranslationProvider(TranslationProvider i18nProvider, LocaleProvider localeProvider) {
this.bundle = FrameworkUtil.getBundle(this.getClass());
this.i18nProvider = i18nProvider;
this.localeProvider = localeProvider;
this.locale = null;
}

public MieleTranslationProvider(TranslationProvider i18nProvider, LocaleProvider localeProvider, Locale locale) {
this.bundle = FrameworkUtil.getBundle(this.getClass());
this.i18nProvider = i18nProvider;
this.localeProvider = localeProvider;
this.locale = locale;
}

public String getText(String key, String defaultText, @Nullable Object... arguments) {
String text = i18nProvider.getText(bundle, key, defaultText,
locale != null ? locale : localeProvider.getLocale(), arguments);
if (text == null) {
return defaultText;
}
return text;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
*/
package org.openhab.binding.miele.internal.handler;

import org.openhab.binding.miele.internal.handler.MieleBridgeHandler.DeviceMetaData;
import org.openhab.binding.miele.internal.DeviceMetaData;
import org.openhab.binding.miele.internal.MieleTranslationProvider;
import org.openhab.core.types.State;

/**
Expand Down Expand Up @@ -51,6 +52,17 @@ public interface ApplianceChannelSelector {
*/
boolean isExtendedState();

/**
* Returns a State for the given string, taking into
* account the metadata provided as well as text
* translations for corresponding numeric values.
*
* @param s - the value to be used to instantiate the State
* @param dmd - the device meta data
* @param translationProvider {@link MieleTranslationProvider} instance
*/
State getState(String s, DeviceMetaData dmd, MieleTranslationProvider translationProvider);

/**
* Returns a State for the given string, taking into
* account the metadata provided. The meta data is sent by
Expand Down
Loading

0 comments on commit 2abba37

Please sign in to comment.