2 * Copyright (c) 2010-2021 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.miele.internal.handler;
15 import static java.util.Map.entry;
16 import static org.openhab.binding.miele.internal.MieleBindingConstants.*;
18 import java.lang.reflect.Method;
19 import java.text.SimpleDateFormat;
20 import java.util.Date;
22 import java.util.Map.Entry;
23 import java.util.TimeZone;
25 import org.apache.commons.lang3.StringUtils;
26 import org.openhab.binding.miele.internal.ExtendedDeviceStateUtil;
27 import org.openhab.binding.miele.internal.handler.MieleBridgeHandler.DeviceMetaData;
28 import org.openhab.core.library.types.DateTimeType;
29 import org.openhab.core.library.types.DecimalType;
30 import org.openhab.core.library.types.OnOffType;
31 import org.openhab.core.library.types.OpenClosedType;
32 import org.openhab.core.library.types.QuantityType;
33 import org.openhab.core.library.types.StringType;
34 import org.openhab.core.types.State;
35 import org.openhab.core.types.Type;
36 import org.openhab.core.types.UnDefType;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
40 import com.google.gson.JsonElement;
43 * The {@link ApplianceChannelSelector} for washing machines
45 * @author Karel Goderis - Initial contribution
46 * @author Kai Kreuzer - Changed START_TIME to DateTimeType
47 * @author Jacob Laursen - Added power/water consumption channels, UoM for temperatures, raw channels
49 public enum WashingMachineChannelSelector implements ApplianceChannelSelector {
51 PRODUCT_TYPE("productTypeId", "productType", StringType.class, true, false),
52 DEVICE_TYPE("mieleDeviceType", "deviceType", StringType.class, true, false),
53 BRAND_ID("brandId", "brandId", StringType.class, true, false),
54 COMPANY_ID("companyId", "companyId", StringType.class, true, false),
55 STATE_TEXT(STATE_PROPERTY_NAME, STATE_TEXT_CHANNEL_ID, StringType.class, false, false),
56 STATE(null, STATE_CHANNEL_ID, DecimalType.class, false, false),
57 PROGRAM_TEXT(PROGRAM_ID_PROPERTY_NAME, PROGRAM_TEXT_CHANNEL_ID, StringType.class, false, false) {
59 public State getState(String s, DeviceMetaData dmd) {
60 State state = getTextState(s, dmd, programs, MISSING_PROGRAM_TEXT_PREFIX);
64 return super.getState(s, dmd);
67 PROGRAM(null, PROGRAM_CHANNEL_ID, DecimalType.class, false, false),
68 PROGRAMTYPE("programType", "type", StringType.class, false, false),
69 PROGRAM_PHASE_TEXT(PHASE_PROPERTY_NAME, PHASE_TEXT_CHANNEL_ID, StringType.class, false, false) {
71 public State getState(String s, DeviceMetaData dmd) {
72 State state = getTextState(s, dmd, phases, MISSING_PHASE_TEXT_PREFIX);
76 return super.getState(s, dmd);
79 PROGRAM_PHASE(RAW_PHASE_PROPERTY_NAME, PHASE_CHANNEL_ID, DecimalType.class, false, false),
80 START_TIME("startTime", "start", DateTimeType.class, false, false) {
82 public State getState(String s, DeviceMetaData dmd) {
83 Date date = new Date();
84 SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
85 dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT+0"));
87 date.setTime(Long.valueOf(s) * 60000);
88 } catch (Exception e) {
91 return getState(dateFormatter.format(date));
94 DURATION("duration", "duration", DateTimeType.class, false, false) {
96 public State getState(String s, DeviceMetaData dmd) {
97 Date date = new Date();
98 SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
99 dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT+0"));
101 date.setTime(Long.valueOf(StringUtils.trim(s)) * 60000);
102 } catch (Exception e) {
105 return getState(dateFormatter.format(date));
108 ELAPSED_TIME("elapsedTime", "elapsed", DateTimeType.class, false, false) {
110 public State getState(String s, DeviceMetaData dmd) {
111 Date date = new Date();
112 SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
113 dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT+0"));
115 date.setTime(Long.valueOf(s) * 60000);
116 } catch (Exception e) {
119 return getState(dateFormatter.format(date));
122 FINISH_TIME("finishTime", "finish", DateTimeType.class, false, false) {
124 public State getState(String s, DeviceMetaData dmd) {
125 Date date = new Date();
126 SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
127 dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT+0"));
129 date.setTime(Long.valueOf(s) * 60000);
130 } catch (Exception e) {
133 return getState(dateFormatter.format(date));
136 TARGET_TEMP("targetTemperature", "target", QuantityType.class, false, false) {
138 public State getState(String s, DeviceMetaData dmd) {
139 return getTemperatureState(s);
142 SPINNING_SPEED("spinningSpeed", "spinningspeed", StringType.class, false, false) {
144 public State getState(String s, DeviceMetaData dmd) {
146 return getState("Without spinning");
148 if ("256".equals(s)) {
149 return getState("Rinsing");
151 return getState(Integer.toString((Integer.valueOf(s))));
154 DOOR("signalDoor", "door", OpenClosedType.class, false, false) {
157 public State getState(String s, DeviceMetaData dmd) {
158 if ("true".equals(s)) {
159 return getState("OPEN");
162 if ("false".equals(s)) {
163 return getState("CLOSED");
166 return UnDefType.UNDEF;
169 SWITCH(null, "switch", OnOffType.class, false, false),
170 POWER_CONSUMPTION(EXTENDED_DEVICE_STATE_PROPERTY_NAME, POWER_CONSUMPTION_CHANNEL_ID, QuantityType.class, false,
172 WATER_CONSUMPTION(EXTENDED_DEVICE_STATE_PROPERTY_NAME, WATER_CONSUMPTION_CHANNEL_ID, QuantityType.class, false,
175 private final Logger logger = LoggerFactory.getLogger(WashingMachineChannelSelector.class);
177 private final static Map<String, String> programs = Map.ofEntries(entry("1", "Cottons"), entry("3", "Minimum iron"),
178 entry("4", "Delicates"), entry("8", "Woollens"), entry("9", "Silks"), entry("17", "Starch"),
179 entry("18", "Rinse"), entry("21", "Drain/Spin"), entry("22", "Curtains"), entry("23", "Shirts"),
180 entry("24", "Denim"), entry("27", "Proofing"), entry("29", "Sportswear"), entry("31", "Automatic Plus"),
181 entry("37", "Outerwear"), entry("39", "Pillows"), entry("50", "Dark Garments"), entry("53", "First wash"),
182 entry("75", "Steam care"), entry("76", "Freshen up"), entry("91", "Maintenance wash"),
183 entry("95", "Down duvets"), entry("122", "Express 20"), entry("129", "Down filled items"),
184 entry("133", "Cottons Eco"), entry("146", "QuickPowerWash"), entry("65532", "Mix"));
186 private final static Map<String, String> phases = Map.ofEntries(entry("1", "Pre-wash"), entry("4", "Washing"),
187 entry("5", "Rinses"), entry("7", "Clean"), entry("9", "Drain"), entry("10", "Spin"),
188 entry("11", "Anti-crease"), entry("12", "Finished"));
190 private final String mieleID;
191 private final String channelID;
192 private final Class<? extends Type> typeClass;
193 private final boolean isProperty;
194 private final boolean isExtendedState;
196 WashingMachineChannelSelector(String propertyID, String channelID, Class<? extends Type> typeClass,
197 boolean isProperty, boolean isExtendedState) {
198 this.mieleID = propertyID;
199 this.channelID = channelID;
200 this.typeClass = typeClass;
201 this.isProperty = isProperty;
202 this.isExtendedState = isExtendedState;
206 public String toString() {
211 public String getMieleID() {
216 public String getChannelID() {
221 public boolean isProperty() {
226 public boolean isExtendedState() {
227 return isExtendedState;
231 public State getState(String s, DeviceMetaData dmd) {
233 String localizedValue = getMieleEnum(s, dmd);
234 if (localizedValue == null) {
235 localizedValue = dmd.LocalizedValue;
237 if (localizedValue == null) {
241 return getState(localizedValue);
247 public State getState(String s) {
249 Method valueOf = typeClass.getMethod("valueOf", String.class);
250 State state = (State) valueOf.invoke(typeClass, s);
254 } catch (Exception e) {
255 logger.error("An exception occurred while converting '{}' into a State", s);
261 public State getTemperatureState(String s) {
263 return ExtendedDeviceStateUtil.getTemperatureState(s);
264 } catch (NumberFormatException e) {
265 logger.warn("An exception occurred while converting '{}' into a State", s);
266 return UnDefType.UNDEF;
270 public State getTextState(String s, DeviceMetaData dmd, Map<String, String> valueMap, String prefix) {
272 return UnDefType.UNDEF;
275 if (dmd == null || dmd.LocalizedValue == null || dmd.LocalizedValue.startsWith(prefix)) {
276 String text = valueMap.get(s);
278 return getState(text);
280 if (dmd == null || dmd.LocalizedValue == null) {
281 return getState(prefix + s);
288 public String getMieleEnum(String s, DeviceMetaData dmd) {
289 if (dmd.MieleEnum != null) {
290 for (Entry<String, JsonElement> enumEntry : dmd.MieleEnum.entrySet()) {
291 if (enumEntry.getValue().getAsString().trim().equals(s.trim())) {
292 return enumEntry.getKey();