* as well as built-in/translated strings.
*/
public static State getStateTextState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ MieleTranslationProvider translationProvider) {
return getTextState(s, dmd, translationProvider, STATES, MISSING_STATE_TEXT_PREFIX, "");
}
* @return Text string as State
*/
public static State getTextState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider, Map<String, String> valueMap, String propertyPrefix,
+ MieleTranslationProvider translationProvider, Map<String, String> valueMap, String propertyPrefix,
String appliancePrefix) {
if ("0".equals(s)) {
return UnDefType.UNDEF;
}
String value = valueMap.get(s);
- if (value != null && translationProvider != null) {
+ if (value != null) {
String key = TEXT_PREFIX + propertyPrefix + appliancePrefix + value;
return new StringType(
translationProvider.getText(key, gatewayText != null ? gatewayText : propertyPrefix + s));
--- /dev/null
+/**
+ * Copyright (c) 2010-2022 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.io.BufferedInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.StringReader;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Random;
+import java.util.zip.GZIPInputStream;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.binding.miele.internal.exceptions.MieleRpcException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonParser;
+
+/**
+ * The {@link MieleGatewayCommunicationController} class is used for communicating with
+ * the XGW 3000 gateway through JSON-RPC.
+ *
+ * @author Jacob Laursen - Initial contribution
+ */
+@NonNullByDefault
+public class MieleGatewayCommunicationController {
+
+ private final URL url;
+ private final Random rand = new Random();
+ private final Gson gson = new Gson();
+ private final Logger logger = LoggerFactory.getLogger(MieleGatewayCommunicationController.class);
+
+ public MieleGatewayCommunicationController(String host) throws MalformedURLException {
+ url = new URL("http://" + host + "/remote/json-rpc");
+ }
+
+ public JsonElement invokeOperation(FullyQualifiedApplianceIdentifier applianceIdentifier, String modelID,
+ String methodName) throws MieleRpcException {
+ Object[] args = new Object[4];
+ args[0] = applianceIdentifier.getUid();
+ args[1] = MieleBindingConstants.MIELE_CLASS + modelID;
+ args[2] = methodName;
+ args[3] = null;
+
+ return invokeRPC("HDAccess/invokeDCOOperation", args);
+ }
+
+ public JsonElement invokeRPC(String methodName, Object[] args) throws MieleRpcException {
+ JsonElement result = null;
+ JsonObject req = new JsonObject();
+ int id = rand.nextInt(Integer.MAX_VALUE);
+ req.addProperty("jsonrpc", "2.0");
+ req.addProperty("id", id);
+ req.addProperty("method", methodName);
+
+ JsonArray params = new JsonArray();
+ for (Object o : args) {
+ params.add(gson.toJsonTree(o));
+ }
+ req.add("params", params);
+
+ String requestData = req.toString();
+ String responseData = null;
+ try {
+ responseData = post(url, Collections.emptyMap(), requestData);
+ } catch (IOException e) {
+ throw new MieleRpcException("Exception occurred while posting data", e);
+ }
+
+ logger.trace("The request '{}' yields '{}'", requestData, responseData);
+ JsonObject parsedResponse = null;
+ try {
+ parsedResponse = (JsonObject) JsonParser.parseReader(new StringReader(responseData));
+ } catch (JsonParseException e) {
+ throw new MieleRpcException("Error parsing JSON response", e);
+ }
+
+ JsonElement error = parsedResponse.get("error");
+ if (error != null && !error.isJsonNull()) {
+ if (error.isJsonPrimitive()) {
+ throw new MieleRpcException("Remote exception occurred: '" + error.getAsString() + "'");
+ } else if (error.isJsonObject()) {
+ JsonObject o = error.getAsJsonObject();
+ Integer code = (o.has("code") ? o.get("code").getAsInt() : null);
+ String message = (o.has("message") ? o.get("message").getAsString() : null);
+ String data = (o.has("data")
+ ? (o.get("data") instanceof JsonObject ? o.get("data").toString() : o.get("data").getAsString())
+ : null);
+ throw new MieleRpcException(
+ "Remote exception occurred: '" + code + "':'" + message + "':'" + data + "'");
+ } else {
+ throw new MieleRpcException("Unknown remote exception occurred: '" + error.toString() + "'");
+ }
+ }
+
+ result = parsedResponse.get("result");
+ if (result == null) {
+ throw new MieleRpcException("Result is missing in response");
+ }
+
+ return result;
+ }
+
+ private String post(URL url, Map<String, String> headers, String data) throws IOException {
+ HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+
+ for (Map.Entry<String, String> entry : headers.entrySet()) {
+ connection.addRequestProperty(entry.getKey(), entry.getValue());
+ }
+
+ connection.addRequestProperty("Accept-Encoding", "gzip");
+ connection.setRequestMethod("POST");
+ connection.setDoOutput(true);
+ connection.connect();
+
+ OutputStream out = null;
+
+ try {
+ out = connection.getOutputStream();
+
+ out.write(data.getBytes());
+ out.flush();
+
+ int statusCode = connection.getResponseCode();
+ if (statusCode != HttpURLConnection.HTTP_OK) {
+ logger.debug("An unexpected status code was returned: '{}'", statusCode);
+ }
+ } finally {
+ if (out != null) {
+ out.close();
+ }
+ }
+
+ String responseEncoding = connection.getHeaderField("Content-Encoding");
+ responseEncoding = (responseEncoding == null ? "" : responseEncoding.trim());
+
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+
+ InputStream in = connection.getInputStream();
+ try {
+ in = connection.getInputStream();
+ if ("gzip".equalsIgnoreCase(responseEncoding)) {
+ in = new GZIPInputStream(in);
+ }
+ in = new BufferedInputStream(in);
+
+ byte[] buff = new byte[1024];
+ int n;
+ while ((n = in.read(buff)) > 0) {
+ bos.write(buff, 0, n);
+ }
+ bos.flush();
+ bos.close();
+ } finally {
+ if (in != null) {
+ in.close();
+ }
+ }
+
+ return bos.toString();
+ }
+}
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.miele.internal.FullyQualifiedApplianceIdentifier;
-import org.openhab.binding.miele.internal.api.dto.DeviceClassObject;
-import org.openhab.binding.miele.internal.api.dto.DeviceProperty;
import org.openhab.binding.miele.internal.api.dto.HomeDevice;
-import org.openhab.binding.miele.internal.handler.ApplianceStatusListener;
+import org.openhab.binding.miele.internal.handler.DiscoveryListener;
import org.openhab.binding.miele.internal.handler.MieleApplianceHandler;
import org.openhab.binding.miele.internal.handler.MieleBridgeHandler;
import org.openhab.core.config.discovery.AbstractDiscoveryService;
* @author Jacob Laursen - Fixed multicast and protocol support (ZigBee/LAN)
*/
@NonNullByDefault
-public class MieleApplianceDiscoveryService extends AbstractDiscoveryService implements ApplianceStatusListener {
+public class MieleApplianceDiscoveryService extends AbstractDiscoveryService implements DiscoveryListener {
private final Logger logger = LoggerFactory.getLogger(MieleApplianceDiscoveryService.class);
}
public void activate() {
- mieleBridgeHandler.registerApplianceStatusListener(this);
+ mieleBridgeHandler.registerDiscoveryListener(this);
}
@Override
public void deactivate() {
removeOlderResults(new Date().getTime());
- mieleBridgeHandler.unregisterApplianceStatusListener(this);
+ mieleBridgeHandler.unregisterDiscoveryListener(this);
}
@Override
@Override
public void startScan() {
- List<HomeDevice> appliances = mieleBridgeHandler.getHomeDevices();
+ List<HomeDevice> appliances = mieleBridgeHandler.getHomeDevicesEmptyOnFailure();
for (HomeDevice l : appliances) {
onApplianceAddedInternal(l);
}
}
}
- @Override
- public void onApplianceStateChanged(FullyQualifiedApplianceIdentifier applianceIdentifier, DeviceClassObject dco) {
- // nothing to do
- }
-
- @Override
- public void onAppliancePropertyChanged(FullyQualifiedApplianceIdentifier applianceIdentifier, DeviceProperty dp) {
- // nothing to do
- }
-
private @Nullable ThingUID getThingUID(HomeDevice appliance) {
ThingUID bridgeUID = mieleBridgeHandler.getThing().getUID();
String modelId = appliance.getDeviceClass();
* @param dmd - the device meta data
* @param translationProvider {@link MieleTranslationProvider} instance
*/
- State getState(String s, @Nullable DeviceMetaData dmd, @Nullable MieleTranslationProvider translationProvider);
+ State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider);
/**
* Returns a State for the given string, taking into
package org.openhab.binding.miele.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.openhab.binding.miele.internal.FullyQualifiedApplianceIdentifier;
import org.openhab.binding.miele.internal.api.dto.DeviceClassObject;
import org.openhab.binding.miele.internal.api.dto.DeviceProperty;
import org.openhab.binding.miele.internal.api.dto.HomeDevice;
/**
- *
- * The {@link ApplianceStatusListener} is notified when an appliance status has changed or
- * an appliance has been removed or added.
+ * The {@link ApplianceStatusListener} is notified when the status for the subscribed
+ * appliance has changed or it has been removed or added.
*
* @author Karel Goderis - Initial contribution
* @author Jacob Laursen - Fixed multicast and protocol support (ZigBee/LAN)
/**
* This method is called whenever the state of the given appliance has changed.
*
- * @param applianceIdentifier the fully qualified identifier of the appliance that has changed
* @param dco the POJO containing the new state (properties and/or operations)
*/
- void onApplianceStateChanged(FullyQualifiedApplianceIdentifier applianceIdentifier, DeviceClassObject dco);
+ void onApplianceStateChanged(DeviceClassObject dco);
/**
* This method is called whenever a "property" of the given appliance has changed.
*
- * @param applianceIdentifier the fully qualified identifier of the appliance that has changed
* @param dco the POJO containing the new state of the property
*/
- void onAppliancePropertyChanged(FullyQualifiedApplianceIdentifier applianceIdentifier, DeviceProperty dp);
+ void onAppliancePropertyChanged(DeviceProperty dp);
/**
* This method is called whenever an appliance is removed.
- *
- * @param appliance The XGW homedevice definition of the appliance that was removed
*/
- void onApplianceRemoved(HomeDevice appliance);
+ void onApplianceRemoved();
/**
* This method is called whenever an appliance is added.
*
- * @param appliance The XGW homedevice definition of the appliance that was removed
+ * @param appliance The XGW homedevice definition of the appliance that was added
*/
void onApplianceAdded(HomeDevice appliance);
}
DEVICE_TYPE("mieleDeviceType", "deviceType", StringType.class, true),
STATE_TEXT(STATE_PROPERTY_NAME, STATE_TEXT_CHANNEL_ID, StringType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return DeviceUtil.getStateTextState(s, dmd, translationProvider);
}
},
STATE("", STATE_CHANNEL_ID, DecimalType.class, false),
PROGRAM_TEXT(PROGRAM_ID_PROPERTY_NAME, PROGRAM_TEXT_CHANNEL_ID, StringType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return DeviceUtil.getTextState(s, dmd, translationProvider, PROGRAMS, MISSING_PROGRAM_TEXT_PREFIX,
MIELE_COFFEE_MACHINE_TEXT_PREFIX);
}
PROGRAMTYPE("programType", "type", StringType.class, false),
PROGRAM_PHASE_TEXT(PHASE_PROPERTY_NAME, PHASE_TEXT_CHANNEL_ID, StringType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return DeviceUtil.getTextState(s, dmd, translationProvider, PHASES, MISSING_PHASE_TEXT_PREFIX,
MIELE_COFFEE_MACHINE_TEXT_PREFIX);
}
// lightingStatus signalFailure signalInfo
DOOR("signalDoor", "door", OpenClosedType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
if ("true".equals(s)) {
return getState("OPEN");
}
}
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return this.getState(s, dmd);
}
return state;
}
} catch (Exception e) {
- logger.error("An exception occurred while converting '{}' into a State", s);
+ logger.warn("An exception occurred while converting '{}' into a State", s);
}
return UnDefType.UNDEF;
*/
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.MIELE_DEVICE_CLASS_COFFEE_SYSTEM;
import org.eclipse.jdt.annotation.NonNullByDefault;
super.handleCommand(channelUID, command);
String channelID = channelUID.getId();
- String applianceId = (String) getThing().getConfiguration().getProperties().get(APPLIANCE_ID);
+ String applianceId = this.applianceId;
if (applianceId == null) {
logger.warn("Command '{}' failed, appliance id is unknown", command);
return;
try {
switch (selector) {
case SWITCH: {
- MieleBridgeHandler bridgeHandler = this.bridgeHandler;
+ MieleBridgeHandler bridgeHandler = getMieleBridgeHandler();
if (bridgeHandler == null) {
logger.warn("Command '{}' failed, missing bridge handler", command);
return;
--- /dev/null
+/**
+ * Copyright (c) 2010-2022 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;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.binding.miele.internal.api.dto.HomeDevice;
+
+/**
+ * The {@link DiscoveryListener} is notified when any appliance has been removed or added.
+ *
+ * @author Jacob Laursen - Initial contribution
+ */
+@NonNullByDefault
+public interface DiscoveryListener {
+
+ /**
+ * This method is called whenever any appliance is removed.
+ *
+ * @param appliance The XGW homedevice definition of the appliance that was removed
+ */
+ void onApplianceRemoved(HomeDevice appliance);
+
+ /**
+ * This method is called whenever any appliance is added.
+ *
+ * @param appliance The XGW homedevice definition of the appliance that was added
+ */
+ void onApplianceAdded(HomeDevice appliance);
+}
*/
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.MIELE_DEVICE_CLASS_DISHWASHER;
import static org.openhab.binding.miele.internal.MieleBindingConstants.POWER_CONSUMPTION_CHANNEL_ID;
import static org.openhab.binding.miele.internal.MieleBindingConstants.WATER_CONSUMPTION_CHANNEL_ID;
super.handleCommand(channelUID, command);
String channelID = channelUID.getId();
- String applianceId = (String) getThing().getConfiguration().getProperties().get(APPLIANCE_ID);
+ String applianceId = this.applianceId;
if (applianceId == null) {
logger.warn("Command '{}' failed, appliance id is unknown", command);
return;
try {
switch (selector) {
case SWITCH: {
- MieleBridgeHandler bridgeHandler = this.bridgeHandler;
+ MieleBridgeHandler bridgeHandler = getMieleBridgeHandler();
if (bridgeHandler == null) {
logger.warn("Command '{}' failed, missing bridge handler", command);
return;
DEVICE_TYPE("mieleDeviceType", "deviceType", StringType.class, true, false),
STATE_TEXT(STATE_PROPERTY_NAME, STATE_TEXT_CHANNEL_ID, StringType.class, false, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return DeviceUtil.getStateTextState(s, dmd, translationProvider);
}
},
STATE("", STATE_CHANNEL_ID, DecimalType.class, false, false),
PROGRAM_TEXT(PROGRAM_ID_PROPERTY_NAME, PROGRAM_TEXT_CHANNEL_ID, StringType.class, false, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return DeviceUtil.getTextState(s, dmd, translationProvider, PROGRAMS, MISSING_PROGRAM_TEXT_PREFIX,
MIELE_DISHWASHER_TEXT_PREFIX);
}
PROGRAM("", PROGRAM_CHANNEL_ID, DecimalType.class, false, false),
PROGRAM_PHASE_TEXT(PHASE_PROPERTY_NAME, PHASE_TEXT_CHANNEL_ID, StringType.class, false, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return DeviceUtil.getTextState(s, dmd, translationProvider, PHASES, MISSING_PHASE_TEXT_PREFIX,
MIELE_DISHWASHER_TEXT_PREFIX);
}
PROGRAM_PHASE(RAW_PHASE_PROPERTY_NAME, PHASE_CHANNEL_ID, DecimalType.class, false, false),
START_TIME("startTime", "start", DateTimeType.class, false, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
Date date = new Date();
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT+0"));
},
DURATION("duration", "duration", DateTimeType.class, false, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
Date date = new Date();
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT+0"));
},
ELAPSED_TIME("elapsedTime", "elapsed", DateTimeType.class, false, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
Date date = new Date();
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT+0"));
},
FINISH_TIME("finishTime", "finish", DateTimeType.class, false, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
Date date = new Date();
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT+0"));
},
DOOR("signalDoor", "door", OpenClosedType.class, false, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
if ("true".equals(s)) {
return getState("OPEN");
}
}
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return this.getState(s, dmd);
}
return state;
}
} catch (Exception e) {
- logger.error("An exception occurred while converting '{}' into a State", s);
+ logger.warn("An exception occurred while converting '{}' into a State", s);
}
return UnDefType.UNDEF;
DEVICE_TYPE("mieleDeviceType", "deviceType", StringType.class, true),
STATE_TEXT(STATE_PROPERTY_NAME, STATE_TEXT_CHANNEL_ID, StringType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return DeviceUtil.getStateTextState(s, dmd, translationProvider);
}
},
SUPERCOOL("", SUPERCOOL_CHANNEL_ID, OnOffType.class, false),
FRIDGECURRENTTEMP("currentTemperature", "current", QuantityType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return getTemperatureState(s);
}
},
FRIDGETARGETTEMP("targetTemperature", "target", QuantityType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return getTemperatureState(s);
}
},
DOOR("signalDoor", "door", OpenClosedType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
if ("true".equals(s)) {
return getState("OPEN");
}
}
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return this.getState(s, dmd);
}
return state;
}
} catch (Exception e) {
- logger.error("An exception occurred while converting '{}' into a State", s);
+ logger.warn("An exception occurred while converting '{}' into a State", s);
}
return UnDefType.UNDEF;
DEVICE_TYPE("mieleDeviceType", "deviceType", StringType.class, true),
STATE_TEXT(STATE_PROPERTY_NAME, STATE_TEXT_CHANNEL_ID, StringType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return DeviceUtil.getStateTextState(s, dmd, translationProvider);
}
},
SUPERFREEZE("", SUPERFREEZE_CHANNEL_ID, OnOffType.class, false),
FREEZERCURRENTTEMP("freezerCurrentTemperature", "freezercurrent", QuantityType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return getTemperatureState(s);
}
},
FREEZERTARGETTEMP("freezerTargetTemperature", "freezertarget", QuantityType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return getTemperatureState(s);
}
},
FRIDGECURRENTTEMP("fridgeCurrentTemperature", "fridgecurrent", QuantityType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return getTemperatureState(s);
}
},
FRIDGETARGETTEMP("fridgeTargetTemperature", "fridgetarget", QuantityType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return getTemperatureState(s);
}
},
DOOR("signalDoor", "door", OpenClosedType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
if ("true".equals(s)) {
return getState("OPEN");
}
}
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return this.getState(s, dmd);
}
return state;
}
} catch (Exception e) {
- logger.error("An exception occurred while converting '{}' into a State", s);
+ logger.warn("An exception occurred while converting '{}' into a State", s);
}
return UnDefType.UNDEF;
super.handleCommand(channelUID, command);
String channelID = channelUID.getId();
- String applianceId = (String) getThing().getConfiguration().getProperties().get(APPLIANCE_ID);
+ String applianceId = this.applianceId;
if (applianceId == null) {
logger.warn("Command '{}' failed, appliance id is unknown", command);
return;
JsonElement result = null;
try {
- MieleBridgeHandler bridgeHandler = this.bridgeHandler;
+ MieleBridgeHandler bridgeHandler = getMieleBridgeHandler();
if (bridgeHandler == null) {
logger.warn("Command '{}' failed, missing bridge handler", command);
return;
}
@Override
- protected void onAppliancePropertyChanged(DeviceProperty dp) {
+ public void onAppliancePropertyChanged(DeviceProperty dp) {
super.onAppliancePropertyChanged(dp);
if (!STATE_PROPERTY_NAME.equals(dp.Name)) {
super.handleCommand(channelUID, command);
String channelID = channelUID.getId();
- String applianceId = (String) getThing().getConfiguration().getProperties().get(APPLIANCE_ID);
+ String applianceId = this.applianceId;
if (applianceId == null) {
logger.warn("Command '{}' failed, appliance id is unknown", command);
return;
JsonElement result = null;
try {
- MieleBridgeHandler bridgeHandler = this.bridgeHandler;
+ MieleBridgeHandler bridgeHandler = getMieleBridgeHandler();
if (bridgeHandler == null) {
logger.warn("Command '{}' failed, missing bridge handler", command);
return;
}
@Override
- protected void onAppliancePropertyChanged(DeviceProperty dp) {
+ public void onAppliancePropertyChanged(DeviceProperty dp) {
super.onAppliancePropertyChanged(dp);
if (!STATE_PROPERTY_NAME.equals(dp.Name)) {
DEVICE_TYPE("mieleDeviceType", "deviceType", StringType.class, true),
STATE_TEXT(STATE_PROPERTY_NAME, STATE_TEXT_CHANNEL_ID, StringType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return DeviceUtil.getStateTextState(s, dmd, translationProvider);
}
},
PLATE1_POWER("plate1PowerStep", "plate1power", DecimalType.class, false),
PLATE1_HEAT("plate1RemainingHeat", "plate1heat", DecimalType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
// If there is remaining heat, the device metadata contains some informative string which can not be
// converted into a DecimalType. We therefore ignore the metadata and return the device property value as a
// State
PLATE2_POWER("plate2PowerStep", "plate2power", DecimalType.class, false),
PLATE2_HEAT("plate2RemainingHeat", "plate2heat", DecimalType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return getState(s);
}
},
PLATE3_POWER("plate3PowerStep", "plate3power", DecimalType.class, false),
PLATE3_HEAT("plate3RemainingHeat", "plate3heat", DecimalType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return getState(s);
}
},
PLATE4_POWER("plate4PowerStep", "plate4power", DecimalType.class, false),
PLATE4_HEAT("plate4RemainingHeat", "plate4heat", DecimalType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return getState(s);
}
},
PLATE5_POWER("plate5PowerStep", "plate5power", DecimalType.class, false),
PLATE5_HEAT("plate5RemainingHeat", "plate5heat", DecimalType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return getState(s);
}
},
PLATE6_POWER("plate6PowerStep", "plate6power", DecimalType.class, false),
PLATE6_HEAT("plate6RemainingHeat", "plate6heat", DecimalType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return getState(s);
}
},
}
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return this.getState(s, dmd);
}
return state;
}
} catch (Exception e) {
- logger.error("An exception occurred while converting '{}' into a State", s);
+ logger.warn("An exception occurred while converting '{}' into a State", s);
}
return UnDefType.UNDEF;
DEVICE_TYPE("mieleDeviceType", "deviceType", StringType.class, true),
STATE_TEXT(STATE_PROPERTY_NAME, STATE_TEXT_CHANNEL_ID, StringType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return DeviceUtil.getStateTextState(s, dmd, translationProvider);
}
},
LIGHT("lightingStatus", "light", OnOffType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
if ("true".equals(s)) {
return getState("ON");
}
}
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return this.getState(s, dmd);
}
return state;
}
} catch (Exception e) {
- logger.error("An exception occurred while converting '{}' into a State", s);
+ logger.warn("An exception occurred while converting '{}' into a State", s);
}
return UnDefType.UNDEF;
*/
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.MIELE_DEVICE_CLASS_HOOD;
import org.eclipse.jdt.annotation.NonNullByDefault;
super.handleCommand(channelUID, command);
String channelID = channelUID.getId();
- String applianceId = (String) getThing().getConfiguration().getProperties().get(APPLIANCE_ID);
+ String applianceId = this.applianceId;
if (applianceId == null) {
logger.warn("Command '{}' failed, appliance id is unknown", command);
return;
JsonElement result = null;
try {
- MieleBridgeHandler bridgeHandler = this.bridgeHandler;
+ MieleBridgeHandler bridgeHandler = getMieleBridgeHandler();
if (bridgeHandler == null) {
logger.warn("Command '{}' failed, missing bridge handler", command);
return;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.miele.internal.DeviceUtil;
-import org.openhab.binding.miele.internal.FullyQualifiedApplianceIdentifier;
import org.openhab.binding.miele.internal.MieleTranslationProvider;
import org.openhab.binding.miele.internal.api.dto.DeviceClassObject;
import org.openhab.binding.miele.internal.api.dto.DeviceMetaData;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
-import org.openhab.core.thing.ThingStatusInfo;
+import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.ThingTypeUID;
+import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.types.Command;
protected Gson gson = new Gson();
protected @Nullable String applianceId;
- protected @Nullable MieleBridgeHandler bridgeHandler;
+ private @Nullable MieleBridgeHandler bridgeHandler;
protected TranslationProvider i18nProvider;
protected LocaleProvider localeProvider;
- protected @Nullable MieleTranslationProvider translationProvider;
+ protected MieleTranslationProvider translationProvider;
private Class<E> selectorType;
protected String modelID;
this.localeProvider = localeProvider;
this.selectorType = selectorType;
this.modelID = modelID;
+ this.translationProvider = new MieleTranslationProvider(i18nProvider, localeProvider);
}
public ApplianceChannelSelector getValueSelectorFromChannelID(String valueSelectorText)
public void initialize() {
logger.debug("Initializing Miele appliance handler.");
final String applianceId = (String) getThing().getConfiguration().getProperties().get(APPLIANCE_ID);
- if (applianceId != null) {
- this.applianceId = applianceId;
- this.onBridgeConnectionResumed();
+ if (applianceId == null || applianceId.isBlank()) {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR,
+ "@text/offline.configuration-error.uid-not-set");
+ return;
}
- }
-
- public void onBridgeConnectionResumed() {
+ this.applianceId = applianceId;
Bridge bridge = getBridge();
- if (bridge != null && getMieleBridgeHandler() != null) {
- ThingStatusInfo statusInfo = bridge.getStatusInfo();
- updateStatus(statusInfo.getStatus(), statusInfo.getStatusDetail(), statusInfo.getDescription());
- initializeTranslationProvider(bridge);
+ if (bridge == null) {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR,
+ "@text/offline.configuration-error.bridge-missing");
+ return;
+ }
+ initializeTranslationProvider(bridge);
+ updateStatus(ThingStatus.UNKNOWN);
+
+ MieleBridgeHandler bridgeHandler = getMieleBridgeHandler();
+ if (bridgeHandler != null) {
+ bridgeHandler.registerApplianceStatusListener(applianceId, this);
}
}
try {
locale = new Locale.Builder().setLanguageTag(language).build();
} catch (IllformedLocaleException e) {
- logger.error("Invalid language configured: {}", e.getMessage());
+ logger.warn("Invalid language configured: {}", e.getMessage());
}
}
if (locale == null) {
@Override
public void dispose() {
logger.debug("Handler disposes. Unregistering listener.");
+ String applianceId = this.applianceId;
if (applianceId != null) {
MieleBridgeHandler bridgeHandler = getMieleBridgeHandler();
if (bridgeHandler != null) {
- bridgeHandler.unregisterApplianceStatusListener(this);
+ bridgeHandler.unregisterApplianceStatusListener(applianceId, this);
}
applianceId = null;
}
}
@Override
- public void onApplianceStateChanged(FullyQualifiedApplianceIdentifier applicationIdentifier,
- DeviceClassObject dco) {
- String applianceId = this.applianceId;
- if (applianceId == null || !applianceId.equals(applicationIdentifier.getApplianceId())) {
- return;
- }
-
+ public void onApplianceStateChanged(DeviceClassObject dco) {
JsonArray properties = dco.Properties;
if (properties == null) {
return;
dp.Value = dp.Value.trim();
dp.Value = dp.Value.strip();
}
- onAppliancePropertyChanged(applicationIdentifier, dp);
+ onAppliancePropertyChanged(dp);
} catch (Exception p) {
// Ignore - this is due to an unrecognized and not yet reverse-engineered array property
}
}
@Override
- public void onAppliancePropertyChanged(FullyQualifiedApplianceIdentifier applicationIdentifier, DeviceProperty dp) {
- String applianceId = this.applianceId;
-
- if (applianceId == null || !applianceId.equals(applicationIdentifier.getApplianceId())) {
- return;
- }
-
- this.onAppliancePropertyChanged(dp);
- }
-
- protected void onAppliancePropertyChanged(DeviceProperty dp) {
+ public void onAppliancePropertyChanged(DeviceProperty dp) {
try {
DeviceMetaData dmd = null;
if (dp.Metadata == null) {
String dpValue = dp.Value.strip().trim();
if (selector != null) {
- if (!selector.isProperty()) {
- ChannelUID theChannelUID = new ChannelUID(getThing().getUID(), selector.getChannelID());
-
- State state = selector.getState(dpValue, dmd, this.translationProvider);
+ String channelId = selector.getChannelID();
+ ThingUID thingUid = getThing().getUID();
+ State state = selector.getState(dpValue, dmd, this.translationProvider);
+ if (selector.isProperty()) {
+ String value = state.toString();
+ logger.trace("Updating the property '{}' of '{}' to '{}'", channelId, thingUid, value);
+ updateProperty(channelId, value);
+ } else {
+ ChannelUID theChannelUID = new ChannelUID(thingUid, channelId);
logger.trace("Update state of {} with getState '{}'", theChannelUID, state);
updateState(theChannelUID, state);
updateRawChannel(dp.Name, dpValue);
- } else {
- logger.debug("Updating the property '{}' of '{}' to '{}'", selector.getChannelID(),
- getThing().getUID(), selector.getState(dpValue, dmd, this.translationProvider).toString());
- Map<String, String> properties = editProperties();
- properties.put(selector.getChannelID(),
- selector.getState(dpValue, dmd, this.translationProvider).toString());
- updateProperties(properties);
}
}
} catch (IllegalArgumentException e) {
- logger.error("An exception occurred while processing a changed device property :'{}'", e.getMessage());
+ logger.warn("An exception occurred while processing a changed device property: '{}'", e.getMessage());
}
}
}
@Override
- public void onApplianceRemoved(HomeDevice appliance) {
- String applianceId = this.applianceId;
- if (applianceId == null) {
- return;
- }
-
- FullyQualifiedApplianceIdentifier applianceIdentifier = appliance.getApplianceIdentifier();
- if (applianceIdentifier == null) {
- return;
- }
-
- if (applianceId.equals(applianceIdentifier.getApplianceId())) {
- updateStatus(ThingStatus.OFFLINE);
- }
+ public void onApplianceRemoved() {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.GONE);
}
@Override
public void onApplianceAdded(HomeDevice appliance) {
- String applianceId = this.applianceId;
- if (applianceId == null) {
- return;
+ Map<String, String> properties = editProperties();
+ String vendor = appliance.Vendor;
+ if (vendor != null) {
+ properties.put(Thing.PROPERTY_VENDOR, vendor);
}
-
- FullyQualifiedApplianceIdentifier applianceIdentifier = appliance.getApplianceIdentifier();
- if (applianceIdentifier == null) {
- return;
+ properties.put(Thing.PROPERTY_MODEL_ID, appliance.getApplianceModel());
+ properties.put(Thing.PROPERTY_SERIAL_NUMBER, appliance.getSerialNumber());
+ properties.put(Thing.PROPERTY_FIRMWARE_VERSION, appliance.getFirmwareVersion());
+ String protocolAdapterName = appliance.ProtocolAdapterName;
+ if (protocolAdapterName != null) {
+ properties.put(PROPERTY_PROTOCOL_ADAPTER, protocolAdapterName);
}
-
- if (applianceId.equals(applianceIdentifier.getApplianceId())) {
- Map<String, String> properties = editProperties();
- String vendor = appliance.Vendor;
- if (vendor != null) {
- properties.put(Thing.PROPERTY_VENDOR, vendor);
- }
- properties.put(Thing.PROPERTY_MODEL_ID, appliance.getApplianceModel());
- properties.put(Thing.PROPERTY_SERIAL_NUMBER, appliance.getSerialNumber());
- properties.put(Thing.PROPERTY_FIRMWARE_VERSION, appliance.getFirmwareVersion());
- String protocolAdapterName = appliance.ProtocolAdapterName;
- if (protocolAdapterName != null) {
- properties.put(PROPERTY_PROTOCOL_ADAPTER, protocolAdapterName);
- }
- String deviceClass = appliance.getDeviceClass();
- if (deviceClass != null) {
- properties.put(PROPERTY_DEVICE_CLASS, deviceClass);
- }
- String connectionType = appliance.getConnectionType();
- if (connectionType != null) {
- properties.put(PROPERTY_CONNECTION_TYPE, connectionType);
- }
- String connectionBaudRate = appliance.getConnectionBaudRate();
- if (connectionBaudRate != null) {
- properties.put(PROPERTY_CONNECTION_BAUD_RATE, connectionBaudRate);
- }
- updateProperties(properties);
- updateStatus(ThingStatus.ONLINE);
+ String deviceClass = appliance.getDeviceClass();
+ if (deviceClass != null) {
+ properties.put(PROPERTY_DEVICE_CLASS, deviceClass);
+ }
+ String connectionType = appliance.getConnectionType();
+ if (connectionType != null) {
+ properties.put(PROPERTY_CONNECTION_TYPE, connectionType);
}
+ String connectionBaudRate = appliance.getConnectionBaudRate();
+ if (connectionBaudRate != null) {
+ properties.put(PROPERTY_CONNECTION_BAUD_RATE, connectionBaudRate);
+ }
+ updateProperties(properties);
+ updateStatus(ThingStatus.ONLINE);
}
- private synchronized @Nullable MieleBridgeHandler getMieleBridgeHandler() {
+ protected synchronized @Nullable MieleBridgeHandler getMieleBridgeHandler() {
if (this.bridgeHandler == null) {
Bridge bridge = getBridge();
if (bridge == null) {
}
ThingHandler handler = bridge.getHandler();
if (handler instanceof MieleBridgeHandler) {
- var bridgeHandler = (MieleBridgeHandler) handler;
- this.bridgeHandler = bridgeHandler;
- bridgeHandler.registerApplianceStatusListener(this);
- } else {
- return null;
+ this.bridgeHandler = (MieleBridgeHandler) handler;
}
}
return this.bridgeHandler;
import static org.openhab.binding.miele.internal.MieleBindingConstants.*;
-import java.io.BufferedInputStream;
-import java.io.ByteArrayOutputStream;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.StringReader;
import java.net.DatagramPacket;
-import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.MulticastSocket;
import java.net.SocketTimeoutException;
-import java.net.URL;
import java.net.UnknownHostException;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.IllformedLocaleException;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
-import java.util.Random;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
-import java.util.zip.GZIPInputStream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.miele.internal.FullyQualifiedApplianceIdentifier;
+import org.openhab.binding.miele.internal.MieleGatewayCommunicationController;
import org.openhab.binding.miele.internal.api.dto.DeviceClassObject;
import org.openhab.binding.miele.internal.api.dto.DeviceProperty;
import org.openhab.binding.miele.internal.api.dto.HomeDevice;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ChannelUID;
-import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.ThingTypeUID;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
-import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonParseException;
-import com.google.gson.JsonParser;
/**
* The {@link MieleBridgeHandler} is responsible for handling commands, which are
private static final Pattern IP_PATTERN = Pattern
.compile("^(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])$");
- protected static final int POLLING_PERIOD = 15; // in seconds
- protected static final int JSON_RPC_PORT = 2810;
- protected static final String JSON_RPC_MULTICAST_IP1 = "239.255.68.139";
- protected static final String JSON_RPC_MULTICAST_IP2 = "224.255.68.139";
- private boolean lastBridgeConnectionState = false;
- private boolean currentBridgeConnectionState = false;
+ private static final int POLLING_PERIOD = 15; // in seconds
+ private static final int JSON_RPC_PORT = 2810;
+ private static final String JSON_RPC_MULTICAST_IP1 = "239.255.68.139";
+ private static final String JSON_RPC_MULTICAST_IP2 = "224.255.68.139";
- protected Random rand = new Random();
- protected Gson gson = new Gson();
private final Logger logger = LoggerFactory.getLogger(MieleBridgeHandler.class);
- protected List<ApplianceStatusListener> applianceStatusListeners = new CopyOnWriteArrayList<>();
- protected @Nullable ScheduledFuture<?> pollingJob;
- protected @Nullable ExecutorService executor;
- protected @Nullable Future<?> eventListenerJob;
+ private boolean lastBridgeConnectionState = false;
+
+ private Gson gson = new Gson();
+ private @NonNullByDefault({}) MieleGatewayCommunicationController gatewayCommunication;
- protected Map<String, HomeDevice> cachedHomeDevicesByApplianceId = new ConcurrentHashMap<String, HomeDevice>();
- protected Map<String, HomeDevice> cachedHomeDevicesByRemoteUid = new ConcurrentHashMap<String, HomeDevice>();
+ private Set<DiscoveryListener> discoveryListeners = ConcurrentHashMap.newKeySet();
+ private Map<String, ApplianceStatusListener> applianceStatusListeners = new ConcurrentHashMap<>();
+ private @Nullable ScheduledFuture<?> pollingJob;
+ private @Nullable ExecutorService executor;
+ private @Nullable Future<?> eventListenerJob;
- protected @Nullable URL url;
+ private Map<String, HomeDevice> cachedHomeDevicesByApplianceId = new ConcurrentHashMap<>();
+ private Map<String, HomeDevice> cachedHomeDevicesByRemoteUid = new ConcurrentHashMap<>();
public MieleBridgeHandler(Bridge bridge) {
super(bridge);
}
try {
- url = new URL("http://" + (String) getConfig().get(HOST) + "/remote/json-rpc");
+ gatewayCommunication = new MieleGatewayCommunicationController((String) getConfig().get(HOST));
} catch (MalformedURLException e) {
- logger.debug("An exception occurred while defining an URL :'{}'", e.getMessage());
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR, e.getMessage());
return;
}
- onUpdate();
- lastBridgeConnectionState = false;
updateStatus(ThingStatus.UNKNOWN);
+ lastBridgeConnectionState = false;
+ schedulePollingAndEventListener();
}
private boolean validateConfig(Configuration config) {
private Runnable pollingRunnable = new Runnable() {
@Override
public void run() {
- if (!IP_PATTERN.matcher((String) getConfig().get(HOST)).matches()) {
- logger.debug("Invalid IP address for the Miele@Home gateway : '{}'", getConfig().get(HOST));
- return;
- }
-
+ String host = (String) getConfig().get(HOST);
try {
- if (isReachable((String) getConfig().get(HOST))) {
- currentBridgeConnectionState = true;
- } else {
- currentBridgeConnectionState = false;
- lastBridgeConnectionState = false;
- onConnectionLost();
- }
+ List<HomeDevice> homeDevices = getHomeDevices();
- if (!lastBridgeConnectionState && currentBridgeConnectionState) {
- logger.debug("Connection to Miele Gateway {} established.", getConfig().get(HOST));
+ if (!lastBridgeConnectionState) {
+ logger.debug("Connection to Miele Gateway {} established.", host);
lastBridgeConnectionState = true;
- onConnectionResumed();
- }
-
- if (!currentBridgeConnectionState || getThing().getStatus() != ThingStatus.ONLINE) {
- return;
}
-
- List<HomeDevice> homeDevices = getHomeDevices();
- for (HomeDevice hd : homeDevices) {
- String key = hd.getApplianceIdentifier().getApplianceId();
- if (!cachedHomeDevicesByApplianceId.containsKey(key)) {
- logger.debug("A new appliance with ID '{}' has been added", hd.UID);
- for (ApplianceStatusListener listener : applianceStatusListeners) {
- listener.onApplianceAdded(hd);
- }
+ updateStatus(ThingStatus.ONLINE);
+
+ refreshHomeDevices(homeDevices);
+
+ for (Entry<String, ApplianceStatusListener> entry : applianceStatusListeners.entrySet()) {
+ String applianceId = entry.getKey();
+ ApplianceStatusListener listener = entry.getValue();
+ FullyQualifiedApplianceIdentifier applianceIdentifier = getApplianceIdentifierFromApplianceId(
+ applianceId);
+ if (applianceIdentifier == null) {
+ logger.debug("The appliance with ID '{}' was not found in appliance list from bridge.",
+ applianceId);
+ listener.onApplianceRemoved();
+ continue;
}
- cachedHomeDevicesByApplianceId.put(key, hd);
- cachedHomeDevicesByRemoteUid.put(hd.getRemoteUid(), hd);
- }
- Set<Entry<String, HomeDevice>> cachedEntries = cachedHomeDevicesByApplianceId.entrySet();
- Iterator<Entry<String, HomeDevice>> iterator = cachedEntries.iterator();
+ Object[] args = new Object[2];
+ args[0] = applianceIdentifier.getUid();
+ args[1] = true;
+ JsonElement result = gatewayCommunication.invokeRPC("HDAccess/getDeviceClassObjects", args);
- while (iterator.hasNext()) {
- Entry<String, HomeDevice> cachedEntry = iterator.next();
- HomeDevice cachedHomeDevice = cachedEntry.getValue();
- if (!homeDevices.stream().anyMatch(d -> d.UID.equals(cachedHomeDevice.UID))) {
- logger.debug("The appliance with ID '{}' has been removed", cachedHomeDevice.UID);
- for (ApplianceStatusListener listener : applianceStatusListeners) {
- listener.onApplianceRemoved(cachedHomeDevice);
- }
- cachedHomeDevicesByRemoteUid.remove(cachedHomeDevice.getRemoteUid());
- iterator.remove();
- }
- }
-
- for (Thing appliance : getThing().getThings()) {
- if (appliance.getStatus() == ThingStatus.ONLINE) {
- String applianceId = (String) appliance.getConfiguration().getProperties().get(APPLIANCE_ID);
- FullyQualifiedApplianceIdentifier applianceIdentifier = null;
- if (applianceId != null) {
- applianceIdentifier = getApplianceIdentifierFromApplianceId(applianceId);
- }
-
- if (applianceIdentifier == null) {
- logger.warn("The appliance with ID '{}' was not found in appliance list from bridge.",
- applianceId);
- continue;
- }
-
- Object[] args = new Object[2];
- args[0] = applianceIdentifier.getUid();
- args[1] = true;
- JsonElement result = invokeRPC("HDAccess/getDeviceClassObjects", args);
-
- for (JsonElement obj : result.getAsJsonArray()) {
- try {
- DeviceClassObject dco = gson.fromJson(obj, DeviceClassObject.class);
-
- // Skip com.prosyst.mbs.services.zigbee.hdm.deviceclasses.ReportingControl
- if (dco == null || !dco.DeviceClass.startsWith(MIELE_CLASS)) {
- continue;
- }
+ for (JsonElement obj : result.getAsJsonArray()) {
+ try {
+ DeviceClassObject dco = gson.fromJson(obj, DeviceClassObject.class);
- for (ApplianceStatusListener listener : applianceStatusListeners) {
- listener.onApplianceStateChanged(applianceIdentifier, dco);
- }
- } catch (Exception e) {
- logger.debug("An exception occurred while querying an appliance : '{}'",
- e.getMessage());
+ // Skip com.prosyst.mbs.services.zigbee.hdm.deviceclasses.ReportingControl
+ if (dco == null || !dco.DeviceClass.startsWith(MIELE_CLASS)) {
+ continue;
}
+
+ listener.onApplianceStateChanged(dco);
+ } catch (Exception e) {
+ logger.debug("An exception occurred while querying an appliance : '{}'", e.getMessage());
}
}
}
logger.debug("An exception occurred while polling an appliance: '{}' -> '{}'", e.getMessage(),
cause.getMessage());
}
+ if (lastBridgeConnectionState) {
+ logger.debug("Connection to Miele Gateway {} lost.", host);
+ lastBridgeConnectionState = false;
+ }
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR);
}
}
+ };
- private boolean isReachable(String ipAddress) {
- try {
- // note that InetAddress.isReachable is unreliable, see
- // http://stackoverflow.com/questions/9922543/why-does-inetaddress-isreachable-return-false-when-i-can-ping-the-ip-address
- // That's why we do an HTTP access instead
+ private synchronized void refreshHomeDevices(List<HomeDevice> homeDevices) {
+ for (HomeDevice hd : homeDevices) {
+ String key = hd.getApplianceIdentifier().getApplianceId();
+ if (!cachedHomeDevicesByApplianceId.containsKey(key)) {
+ logger.debug("A new appliance with ID '{}' has been added", hd.UID);
+ for (DiscoveryListener listener : discoveryListeners) {
+ listener.onApplianceAdded(hd);
+ }
+ ApplianceStatusListener listener = applianceStatusListeners
+ .get(hd.getApplianceIdentifier().getApplianceId());
+ if (listener != null) {
+ listener.onApplianceAdded(hd);
+ }
+ }
+ cachedHomeDevicesByApplianceId.put(key, hd);
+ cachedHomeDevicesByRemoteUid.put(hd.getRemoteUid(), hd);
+ }
- // If there is no connection, this line will fail
- invokeRPC("system.listMethods", new Object[0]);
- } catch (MieleRpcException e) {
- logger.debug("{} is not reachable", ipAddress);
- return false;
+ Set<Entry<String, HomeDevice>> cachedEntries = cachedHomeDevicesByApplianceId.entrySet();
+ Iterator<Entry<String, HomeDevice>> iterator = cachedEntries.iterator();
+
+ while (iterator.hasNext()) {
+ Entry<String, HomeDevice> cachedEntry = iterator.next();
+ HomeDevice cachedHomeDevice = cachedEntry.getValue();
+ if (!homeDevices.stream().anyMatch(d -> d.UID.equals(cachedHomeDevice.UID))) {
+ logger.debug("The appliance with ID '{}' has been removed", cachedHomeDevice.UID);
+ for (DiscoveryListener listener : discoveryListeners) {
+ listener.onApplianceRemoved(cachedHomeDevice);
+ }
+ ApplianceStatusListener listener = applianceStatusListeners
+ .get(cachedHomeDevice.getApplianceIdentifier().getApplianceId());
+ if (listener != null) {
+ listener.onApplianceRemoved();
+ }
+ cachedHomeDevicesByRemoteUid.remove(cachedHomeDevice.getRemoteUid());
+ iterator.remove();
}
+ }
+ }
- logger.debug("{} is reachable", ipAddress);
- return true;
+ public List<HomeDevice> getHomeDevicesEmptyOnFailure() {
+ try {
+ return getHomeDevices();
+ } catch (MieleRpcException e) {
+ Throwable cause = e.getCause();
+ if (cause == null) {
+ logger.debug("An exception occurred while getting the home devices: '{}'", e.getMessage());
+ } else {
+ logger.debug("An exception occurred while getting the home devices: '{}' -> '{}", e.getMessage(),
+ cause.getMessage());
+ }
+ return new ArrayList<>();
}
- };
+ }
- public List<HomeDevice> getHomeDevices() {
+ private List<HomeDevice> getHomeDevices() throws MieleRpcException {
List<HomeDevice> devices = new ArrayList<>();
- if (getThing().getStatus() == ThingStatus.ONLINE) {
- try {
- String[] args = new String[1];
- args[0] = "(type=SuperVision)";
- JsonElement result = invokeRPC("HDAccess/getHomeDevices", args);
-
- for (JsonElement obj : result.getAsJsonArray()) {
- HomeDevice hd = gson.fromJson(obj, HomeDevice.class);
- if (hd != null) {
- devices.add(hd);
- }
- }
- } catch (MieleRpcException e) {
- Throwable cause = e.getCause();
- if (cause == null) {
- logger.debug("An exception occurred while getting the home devices: '{}'", e.getMessage());
- } else {
- logger.debug("An exception occurred while getting the home devices: '{}' -> '{}", e.getMessage(),
- cause.getMessage());
- }
+ if (!isInitialized()) {
+ return devices;
+ }
+
+ String[] args = new String[1];
+ args[0] = "(type=SuperVision)";
+ JsonElement result = gatewayCommunication.invokeRPC("HDAccess/getHomeDevices", args);
+
+ for (JsonElement obj : result.getAsJsonArray()) {
+ HomeDevice hd = gson.fromJson(obj, HomeDevice.class);
+ if (hd != null) {
+ devices.add(hd);
}
}
return devices;
address1 = InetAddress.getByName(JSON_RPC_MULTICAST_IP1);
address2 = InetAddress.getByName(JSON_RPC_MULTICAST_IP2);
} catch (UnknownHostException e) {
- logger.debug("An exception occurred while setting up the multicast receiver : '{}'",
- e.getMessage());
+ logger.debug("An exception occurred while setting up the multicast receiver: '{}'", e.getMessage());
}
byte[] buf = new byte[256];
var deviceProperty = new DeviceProperty();
deviceProperty.Name = name;
deviceProperty.Value = value;
- for (ApplianceStatusListener listener : applianceStatusListeners) {
- listener.onAppliancePropertyChanged(applianceIdentifier, deviceProperty);
+ ApplianceStatusListener listener = applianceStatusListeners
+ .get(applianceIdentifier.getApplianceId());
+ if (listener != null) {
+ listener.onAppliancePropertyChanged(deviceProperty);
}
} catch (SocketTimeoutException e) {
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
- logger.debug("Eventlistener has been interrupted.");
+ logger.debug("Event listener has been interrupted.");
break;
}
}
}
} catch (Exception ex) {
- logger.debug("An exception occurred while receiving multicast packets : '{}'", ex.getMessage());
+ logger.debug("An exception occurred while receiving multicast packets: '{}'", ex.getMessage());
}
// restart the cycle with a clean slate
clientSocket.leaveGroup(address2);
}
} catch (IOException e) {
- logger.debug("An exception occurred while leaving multicast group : '{}'", e.getMessage());
+ logger.debug("An exception occurred while leaving multicast group: '{}'", e.getMessage());
}
if (clientSocket != null) {
clientSocket.close();
}
}
} else {
- logger.debug("Invalid IP address for the multicast interface : '{}'", getConfig().get(INTERFACE));
+ logger.debug("Invalid IP address for the multicast interface: '{}'", getConfig().get(INTERFACE));
}
};
+ " was not found in appliance list from gateway - operations can not be invoked");
}
- Object[] args = new Object[4];
- args[0] = applianceIdentifier.getUid();
- args[1] = MIELE_CLASS + modelID;
- args[2] = methodName;
- args[3] = null;
-
- return invokeRPC("HDAccess/invokeDCOOperation", args);
+ return gatewayCommunication.invokeOperation(applianceIdentifier, modelID, methodName);
}
- protected JsonElement invokeRPC(String methodName, Object[] args) throws MieleRpcException {
- JsonElement result = null;
- URL url = this.url;
- if (url == null) {
- throw new MieleRpcException("URL is not set");
- }
-
- JsonObject req = new JsonObject();
- int id = rand.nextInt(Integer.MAX_VALUE);
- req.addProperty("jsonrpc", "2.0");
- req.addProperty("id", id);
- req.addProperty("method", methodName);
-
- JsonArray params = new JsonArray();
- for (Object o : args) {
- params.add(gson.toJsonTree(o));
- }
- req.add("params", params);
-
- String requestData = req.toString();
- String responseData = null;
- try {
- responseData = post(url, Collections.emptyMap(), requestData);
- } catch (IOException e) {
- throw new MieleRpcException("Exception occurred while posting data", e);
- }
-
- logger.trace("The request '{}' yields '{}'", requestData, responseData);
- JsonObject parsedResponse = null;
- try {
- parsedResponse = (JsonObject) JsonParser.parseReader(new StringReader(responseData));
- } catch (JsonParseException e) {
- throw new MieleRpcException("Error parsing JSON response", e);
- }
-
- JsonElement error = parsedResponse.get("error");
- if (error != null && !error.isJsonNull()) {
- if (error.isJsonPrimitive()) {
- throw new MieleRpcException("Remote exception occurred: '" + error.getAsString() + "'");
- } else if (error.isJsonObject()) {
- JsonObject o = error.getAsJsonObject();
- Integer code = (o.has("code") ? o.get("code").getAsInt() : null);
- String message = (o.has("message") ? o.get("message").getAsString() : null);
- String data = (o.has("data")
- ? (o.get("data") instanceof JsonObject ? o.get("data").toString() : o.get("data").getAsString())
- : null);
- throw new MieleRpcException(
- "Remote exception occurred: '" + code + "':'" + message + "':'" + data + "'");
- } else {
- throw new MieleRpcException("Unknown remote exception occurred: '" + error.toString() + "'");
- }
- }
-
- result = parsedResponse.get("result");
- if (result == null) {
- throw new MieleRpcException("Result is missing in response");
- }
-
- return result;
- }
-
- protected String post(URL url, Map<String, String> headers, String data) throws IOException {
- HttpURLConnection connection = (HttpURLConnection) url.openConnection();
-
- for (Map.Entry<String, String> entry : headers.entrySet()) {
- connection.addRequestProperty(entry.getKey(), entry.getValue());
- }
-
- connection.addRequestProperty("Accept-Encoding", "gzip");
-
- connection.setRequestMethod("POST");
- connection.setDoOutput(true);
- connection.connect();
-
- OutputStream out = null;
-
- try {
- out = connection.getOutputStream();
-
- out.write(data.getBytes());
- out.flush();
-
- int statusCode = connection.getResponseCode();
- if (statusCode != HttpURLConnection.HTTP_OK) {
- logger.debug("An unexpected status code was returned: '{}'", statusCode);
- }
- } finally {
- if (out != null) {
- out.close();
- }
- }
-
- String responseEncoding = connection.getHeaderField("Content-Encoding");
- responseEncoding = (responseEncoding == null ? "" : responseEncoding.trim());
-
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
-
- InputStream in = connection.getInputStream();
- try {
- in = connection.getInputStream();
- if ("gzip".equalsIgnoreCase(responseEncoding)) {
- in = new GZIPInputStream(in);
- }
- in = new BufferedInputStream(in);
-
- byte[] buff = new byte[1024];
- int n;
- while ((n = in.read(buff)) > 0) {
- bos.write(buff, 0, n);
- }
- bos.flush();
- bos.close();
- } finally {
- if (in != null) {
- in.close();
- }
- }
-
- return bos.toString();
- }
-
- private synchronized void onUpdate() {
+ private synchronized void schedulePollingAndEventListener() {
logger.debug("Scheduling the Miele polling job");
ScheduledFuture<?> pollingJob = this.pollingJob;
if (pollingJob == null || pollingJob.isCancelled()) {
this.pollingJob = pollingJob;
logger.trace("Scheduling the Miele polling job Job is done ?{}", pollingJob.isDone());
}
- logger.debug("Scheduling the Miele event listener job");
+ logger.debug("Scheduling the Miele event listener job");
Future<?> eventListenerJob = this.eventListenerJob;
if (eventListenerJob == null || eventListenerJob.isCancelled()) {
ExecutorService executor = Executors
}
}
- /**
- * This method is called whenever the connection to the given {@link MieleBridge} is lost.
- *
- */
- public void onConnectionLost() {
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR);
- }
+ public boolean registerApplianceStatusListener(String applianceId,
+ ApplianceStatusListener applianceStatusListener) {
+ ApplianceStatusListener existingListener = applianceStatusListeners.get(applianceId);
+ if (existingListener != null) {
+ if (!existingListener.equals(applianceStatusListener)) {
+ logger.warn("Unsupported configuration: appliance with ID '{}' referenced by multiple things",
+ applianceId);
+ } else {
+ logger.debug("Duplicate listener registration attempted for '{}'", applianceId);
+ }
+ return false;
+ }
+ applianceStatusListeners.put(applianceId, applianceStatusListener);
- /**
- * This method is called whenever the connection to the given {@link MieleBridge} is resumed.
- *
- * @param bridge the Miele bridge the connection is resumed to
- */
- public void onConnectionResumed() {
- updateStatus(ThingStatus.ONLINE);
- for (Thing thing : getThing().getThings()) {
- MieleApplianceHandler<?> handler = (MieleApplianceHandler<?>) thing.getHandler();
- if (handler != null) {
- handler.onBridgeConnectionResumed();
+ HomeDevice cachedHomeDevice = cachedHomeDevicesByApplianceId.get(applianceId);
+ if (cachedHomeDevice != null) {
+ applianceStatusListener.onApplianceAdded(cachedHomeDevice);
+ } else {
+ try {
+ refreshHomeDevices(getHomeDevices());
+ } catch (MieleRpcException e) {
+ Throwable cause = e.getCause();
+ if (cause == null) {
+ logger.debug("An exception occurred while getting the home devices: '{}'", e.getMessage());
+ } else {
+ logger.debug("An exception occurred while getting the home devices: '{}' -> '{}", e.getMessage(),
+ cause.getMessage());
+ }
}
}
+
+ return true;
}
- public boolean registerApplianceStatusListener(ApplianceStatusListener applianceStatusListener) {
- boolean result = applianceStatusListeners.add(applianceStatusListener);
- if (result && isInitialized()) {
- onUpdate();
+ public boolean unregisterApplianceStatusListener(String applianceId,
+ ApplianceStatusListener applianceStatusListener) {
+ return applianceStatusListeners.remove(applianceId) != null;
+ }
- for (HomeDevice hd : getHomeDevices()) {
- applianceStatusListener.onApplianceAdded(hd);
+ public boolean registerDiscoveryListener(DiscoveryListener discoveryListener) {
+ if (!discoveryListeners.add(discoveryListener)) {
+ return false;
+ }
+ if (cachedHomeDevicesByApplianceId.isEmpty()) {
+ try {
+ refreshHomeDevices(getHomeDevices());
+ } catch (MieleRpcException e) {
+ Throwable cause = e.getCause();
+ if (cause == null) {
+ logger.debug("An exception occurred while getting the home devices: '{}'", e.getMessage());
+ } else {
+ logger.debug("An exception occurred while getting the home devices: '{}' -> '{}", e.getMessage(),
+ cause.getMessage());
+ }
+ }
+ } else {
+ for (Entry<String, HomeDevice> entry : cachedHomeDevicesByApplianceId.entrySet()) {
+ discoveryListener.onApplianceAdded(entry.getValue());
}
}
- return result;
+ return true;
}
- public boolean unregisterApplianceStatusListener(ApplianceStatusListener applianceStatusListener) {
- boolean result = applianceStatusListeners.remove(applianceStatusListener);
- if (result && isInitialized()) {
- onUpdate();
- }
- return result;
+ public boolean unregisterDiscoveryListener(DiscoveryListener discoveryListener) {
+ return discoveryListeners.remove(discoveryListener);
}
@Override
DEVICE_TYPE("mieleDeviceType", "deviceType", StringType.class, true),
STATE_TEXT(STATE_PROPERTY_NAME, STATE_TEXT_CHANNEL_ID, StringType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return DeviceUtil.getStateTextState(s, dmd, translationProvider);
}
},
PROGRAMTYPE("programType", "type", StringType.class, false),
PROGRAM_PHASE_TEXT(PHASE_PROPERTY_NAME, PHASE_TEXT_CHANNEL_ID, StringType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return DeviceUtil.getTextState(s, dmd, translationProvider, PHASES, MISSING_PHASE_TEXT_PREFIX,
MIELE_OVEN_TEXT_PREFIX);
}
PROGRAM_PHASE(RAW_PHASE_PROPERTY_NAME, PHASE_CHANNEL_ID, DecimalType.class, false),
START_TIME("startTime", "start", DateTimeType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
Date date = new Date();
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT+0"));
},
DURATION("duration", "duration", DateTimeType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
Date date = new Date();
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT+0"));
},
ELAPSED_TIME("elapsedTime", "elapsed", DateTimeType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
Date date = new Date();
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT+0"));
},
FINISH_TIME("finishTime", "finish", DateTimeType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
Date date = new Date();
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT+0"));
},
TARGET_TEMP("targetTemperature", "target", QuantityType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return getTemperatureState(s);
}
},
MEASURED_TEMP("measuredTemperature", "measured", QuantityType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return getTemperatureState(s);
}
},
DEVICE_TEMP_ONE("deviceTemperature1", "temp1", QuantityType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return getTemperatureState(s);
}
},
DEVICE_TEMP_TWO("deviceTemperature2", "temp2", QuantityType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return getTemperatureState(s);
}
},
DOOR("signalDoor", "door", OpenClosedType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
if ("true".equals(s)) {
return getState("OPEN");
}
}
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return this.getState(s, dmd);
}
return state;
}
} catch (Exception e) {
- logger.error("An exception occurred while converting '{}' into a State", s);
+ logger.warn("An exception occurred while converting '{}' into a State", s);
}
return UnDefType.UNDEF;
*/
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.MIELE_DEVICE_CLASS_OVEN;
import org.eclipse.jdt.annotation.NonNullByDefault;
super.handleCommand(channelUID, command);
String channelID = channelUID.getId();
- String applianceId = (String) getThing().getConfiguration().getProperties().get(APPLIANCE_ID);
+ String applianceId = this.applianceId;
if (applianceId == null) {
logger.warn("Command '{}' failed, appliance id is unknown", command);
return;
JsonElement result = null;
try {
- MieleBridgeHandler bridgeHandler = this.bridgeHandler;
+ MieleBridgeHandler bridgeHandler = getMieleBridgeHandler();
if (bridgeHandler == null) {
logger.warn("Command '{}' failed, missing bridge handler", command);
return;
DEVICE_TYPE("mieleDeviceType", "deviceType", StringType.class, true),
STATE_TEXT(STATE_PROPERTY_NAME, STATE_TEXT_CHANNEL_ID, StringType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return DeviceUtil.getStateTextState(s, dmd, translationProvider);
}
},
STATE("", STATE_CHANNEL_ID, DecimalType.class, false),
PROGRAM_TEXT(PROGRAM_ID_PROPERTY_NAME, PROGRAM_TEXT_CHANNEL_ID, StringType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return DeviceUtil.getTextState(s, dmd, translationProvider, PROGRAMS, MISSING_PROGRAM_TEXT_PREFIX,
MIELE_TUMBLE_DRYER_TEXT_PREFIX);
}
PROGRAMTYPE("programType", "type", StringType.class, false),
PROGRAM_PHASE_TEXT(PHASE_PROPERTY_NAME, PHASE_TEXT_CHANNEL_ID, StringType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return DeviceUtil.getTextState(s, dmd, translationProvider, PHASES, MISSING_PHASE_TEXT_PREFIX,
MIELE_TUMBLE_DRYER_TEXT_PREFIX);
}
PROGRAM_PHASE(RAW_PHASE_PROPERTY_NAME, PHASE_CHANNEL_ID, DecimalType.class, false),
START_TIME("startTime", "start", DateTimeType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
Date date = new Date();
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT+0"));
},
DURATION("duration", "duration", DateTimeType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
Date date = new Date();
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT+0"));
},
ELAPSED_TIME("elapsedTime", "elapsed", DateTimeType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
Date date = new Date();
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT+0"));
},
FINISH_TIME("finishTime", "finish", DateTimeType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
Date date = new Date();
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT+0"));
},
DRYING_STEP("dryingStep", "step", DecimalType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return getState(s);
}
},
DOOR("signalDoor", "door", OpenClosedType.class, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
if ("true".equals(s)) {
return getState("OPEN");
}
}
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return this.getState(s, dmd);
}
return state;
}
} catch (Exception e) {
- logger.error("An exception occurred while converting '{}' into a State", s);
+ logger.warn("An exception occurred while converting '{}' into a State", s);
}
return UnDefType.UNDEF;
*/
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.MIELE_DEVICE_CLASS_TUMBLE_DRYER;
import org.eclipse.jdt.annotation.NonNullByDefault;
super.handleCommand(channelUID, command);
String channelID = channelUID.getId();
- String applianceId = (String) getThing().getConfiguration().getProperties().get(APPLIANCE_ID);
+ String applianceId = this.applianceId;
if (applianceId == null) {
logger.warn("Command '{}' failed, appliance id is unknown", command);
return;
try {
switch (selector) {
case SWITCH: {
- MieleBridgeHandler bridgeHandler = this.bridgeHandler;
+ MieleBridgeHandler bridgeHandler = getMieleBridgeHandler();
if (bridgeHandler == null) {
logger.warn("Command '{}' failed, missing bridge handler", command);
return;
DEVICE_TYPE("mieleDeviceType", "deviceType", StringType.class, true, false),
STATE_TEXT(STATE_PROPERTY_NAME, STATE_TEXT_CHANNEL_ID, StringType.class, false, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return DeviceUtil.getStateTextState(s, dmd, translationProvider);
}
},
STATE("", STATE_CHANNEL_ID, DecimalType.class, false, false),
PROGRAM_TEXT(PROGRAM_ID_PROPERTY_NAME, PROGRAM_TEXT_CHANNEL_ID, StringType.class, false, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return DeviceUtil.getTextState(s, dmd, translationProvider, PROGRAMS, MISSING_PROGRAM_TEXT_PREFIX,
MIELE_WASHING_MACHINE_TEXT_PREFIX);
}
PROGRAMTYPE("programType", "type", StringType.class, false, false),
PROGRAM_PHASE_TEXT(PHASE_PROPERTY_NAME, PHASE_TEXT_CHANNEL_ID, StringType.class, false, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return DeviceUtil.getTextState(s, dmd, translationProvider, PHASES, MISSING_PHASE_TEXT_PREFIX,
MIELE_WASHING_MACHINE_TEXT_PREFIX);
}
PROGRAM_PHASE(RAW_PHASE_PROPERTY_NAME, PHASE_CHANNEL_ID, DecimalType.class, false, false),
START_TIME("startTime", "start", DateTimeType.class, false, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
Date date = new Date();
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT+0"));
},
DURATION("duration", "duration", DateTimeType.class, false, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
Date date = new Date();
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT+0"));
},
ELAPSED_TIME("elapsedTime", "elapsed", DateTimeType.class, false, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
Date date = new Date();
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT+0"));
},
FINISH_TIME("finishTime", "finish", DateTimeType.class, false, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
Date date = new Date();
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT+0"));
},
TARGET_TEMP("targetTemperature", "target", QuantityType.class, false, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return getTemperatureState(s);
}
},
SPINNING_SPEED("spinningSpeed", "spinningspeed", StringType.class, false, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
if ("0".equals(s)) {
return getState("Without spinning");
}
},
DOOR("signalDoor", "door", OpenClosedType.class, false, false) {
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
if ("true".equals(s)) {
return getState("OPEN");
}
}
@Override
- public State getState(String s, @Nullable DeviceMetaData dmd,
- @Nullable MieleTranslationProvider translationProvider) {
+ public State getState(String s, @Nullable DeviceMetaData dmd, MieleTranslationProvider translationProvider) {
return this.getState(s, dmd);
}
return state;
}
} catch (Exception e) {
- logger.error("An exception occurred while converting '{}' into a State", s);
+ logger.warn("An exception occurred while converting '{}' into a State", s);
}
return UnDefType.UNDEF;
*/
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.MIELE_DEVICE_CLASS_WASHING_MACHINE;
import static org.openhab.binding.miele.internal.MieleBindingConstants.POWER_CONSUMPTION_CHANNEL_ID;
import static org.openhab.binding.miele.internal.MieleBindingConstants.WATER_CONSUMPTION_CHANNEL_ID;
super.handleCommand(channelUID, command);
String channelID = channelUID.getId();
- String applianceId = (String) getThing().getConfiguration().getProperties().get(APPLIANCE_ID);
+ String applianceId = this.applianceId;
if (applianceId == null) {
logger.warn("Command '{}' failed, appliance id is unknown", command);
return;
try {
switch (selector) {
case SWITCH: {
- MieleBridgeHandler bridgeHandler = this.bridgeHandler;
+ MieleBridgeHandler bridgeHandler = getMieleBridgeHandler();
if (bridgeHandler == null) {
logger.warn("Command '{}' failed, missing bridge handler", command);
return;
# thing status descriptions
+offline.configuration-error.bridge-missing = Bridge is missing
offline.configuration-error.ip-address-not-set = Cannot connect to the Miele gateway: host IP address is not set.
offline.configuration-error.ip-multicast-interface-not-set = Cannot connect to the Miele gateway: multicast interface is not set.
offline.configuration-error.invalid-ip-gateway = Invalid IP address for the Miele@Home gateway: {0}
offline.configuration-error.invalid-ip-multicast-interface = Invalid IP address for the multicast interface: {0}
offline.configuration-error.invalid-language = Invalid language: {0}
+offline.configuration-error.uid-not-set = Appliance ID is not set
# Discovery result