]> git.basschouten.com Git - openhab-addons.git/commitdiff
[miele] Clean up properties and improve reliability and performance (#11423)
authorjlaur <jacob-github@vindvejr.dk>
Mon, 1 Nov 2021 17:44:19 +0000 (18:44 +0100)
committerGitHub <noreply@github.com>
Mon, 1 Nov 2021 17:44:19 +0000 (18:44 +0100)
* Use appliance cache for getting full UID with protocol prefix instead of relying on property.
* Set bare protocol name as property.
* Fix potential null pointer access warnings.
* Remove unused import.
* Renamed property protocol to protocolAdapter for correctness.
* Add connectionType property.
* Add appliance model property.
* Remove useless properties brandId and companyId always having value MI.
* Rename property dc to deviceClass and set it consistently (not only from auto-discovered things).
* Added constants for remaining handlers with hardcoded device classes.
* Fix SCA: AuthorContributionDescriptionCheck
* Fix SCA: ModifierOrderCheck
* Rename ExtendedDeviceStateUtil to be a bit more generic.
* Extract device class string parsing to utility method.
* Fix SCA: ForbiddenPackageUsageCheck
* Fix redundant null check.
* Fix potential null pointer access warnings.
* Fix unsafe null type conversion (type annotations)
* Share same configuration (UID) for all appliance types.
* Refer to gateway instead of ZigBee network in configuration.
* Remove dependency to seriaNumber property for multicast channel updates.
* Simplified filtering of irrelevant device class.
* Remove devices from remoteUid cache also when disappearing from gateway, although this is a quite rare scenario.
* Add default i18n properties file.
* Add partial Danish translation.

Fixes #11422

Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
43 files changed:
bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/DeviceUtil.java [new file with mode: 0644]
bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/ExtendedDeviceStateUtil.java [deleted file]
bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/FullyQualifiedApplianceIdentifier.java
bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/MieleBindingConstants.java
bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/discovery/MieleApplianceDiscoveryService.java
bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/discovery/MieleMDNSDiscoveryParticipant.java
bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/ApplianceStatusListener.java
bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/CoffeeMachineChannelSelector.java
bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/CoffeeMachineHandler.java
bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/DishWasherHandler.java
bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/DishwasherChannelSelector.java
bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/FridgeChannelSelector.java
bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/FridgeFreezerChannelSelector.java
bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/FridgeFreezerHandler.java
bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/FridgeHandler.java
bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/HobChannelSelector.java
bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/HobHandler.java
bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/HoodChannelSelector.java
bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/HoodHandler.java
bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/MieleApplianceHandler.java
bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/MieleBridgeHandler.java
bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/OvenChannelSelector.java
bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/OvenHandler.java
bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/TumbleDryerChannelSelector.java
bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/TumbleDryerHandler.java
bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/WashingMachineChannelSelector.java
bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/handler/WashingMachineHandler.java
bundles/org.openhab.binding.miele/src/main/resources/OH-INF/config/config.xml [new file with mode: 0644]
bundles/org.openhab.binding.miele/src/main/resources/OH-INF/i18n/miele.properties [new file with mode: 0644]
bundles/org.openhab.binding.miele/src/main/resources/OH-INF/i18n/miele_da.properties [new file with mode: 0644]
bundles/org.openhab.binding.miele/src/main/resources/OH-INF/thing/coffeemachine.xml
bundles/org.openhab.binding.miele/src/main/resources/OH-INF/thing/dishwasher.xml
bundles/org.openhab.binding.miele/src/main/resources/OH-INF/thing/fridge.xml
bundles/org.openhab.binding.miele/src/main/resources/OH-INF/thing/fridgefreezer.xml
bundles/org.openhab.binding.miele/src/main/resources/OH-INF/thing/hob.xml
bundles/org.openhab.binding.miele/src/main/resources/OH-INF/thing/hood.xml
bundles/org.openhab.binding.miele/src/main/resources/OH-INF/thing/oven.xml
bundles/org.openhab.binding.miele/src/main/resources/OH-INF/thing/tumbledryer.xml
bundles/org.openhab.binding.miele/src/main/resources/OH-INF/thing/washingmachine.xml
bundles/org.openhab.binding.miele/src/main/resources/OH-INF/thing/xgw3000.xml
bundles/org.openhab.binding.miele/src/test/java/org/openhab/binding/miele/internal/DeviceUtilTest.java [new file with mode: 0644]
bundles/org.openhab.binding.miele/src/test/java/org/openhab/binding/miele/internal/ExtendedDeviceStateUtilTest.java [deleted file]
bundles/org.openhab.binding.miele/src/test/java/org/openhab/binding/miele/internal/FullyQualifiedApplianceIdentifierTest.java

diff --git a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/DeviceUtil.java b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/DeviceUtil.java
new file mode 100644 (file)
index 0000000..c80b28d
--- /dev/null
@@ -0,0 +1,66 @@
+/**
+ * Copyright (c) 2010-2021 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.miele.internal;
+
+import java.nio.charset.StandardCharsets;
+
+import org.openhab.core.library.types.QuantityType;
+import org.openhab.core.library.unit.SIUnits;
+import org.openhab.core.types.State;
+import org.openhab.core.types.UnDefType;
+
+/**
+ * The {@link DeviceUtil} class contains utility methods for extracting
+ * and parsing device information, for example from ExtendedDeviceState.
+ *
+ * @author Jacob Laursen - Initial contribution
+ */
+public class DeviceUtil {
+    private static final byte[] HEX_ARRAY = "0123456789ABCDEF".getBytes(StandardCharsets.US_ASCII);
+    private static final String TEMPERATURE_UNDEFINED = "32768";
+
+    /**
+     * Convert byte array to hex representation.
+     */
+    public static String bytesToHex(byte[] bytes) {
+        byte[] hexChars = new byte[bytes.length * 2];
+        for (int j = 0; j < bytes.length; j++) {
+            int v = bytes[j] & 0xFF;
+            hexChars[j * 2] = HEX_ARRAY[v >>> 4];
+            hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
+        }
+
+        return new String(hexChars, StandardCharsets.UTF_8);
+    }
+
+    /**
+     * Convert string consisting of 8 bit characters to byte array.
+     * Note: This simple operation has been extracted and put here to document
+     * and ensure correct behavior for 8 bit characters that should be turned
+     * into single bytes without any UTF-8 encoding.
+     */
+    public static byte[] stringToBytes(String input) {
+        return input.getBytes(StandardCharsets.ISO_8859_1);
+    }
+
+    /**
+     * Convert string to Number:Temperature state with unit Celcius
+     */
+    public static State getTemperatureState(String s) throws NumberFormatException {
+        if (TEMPERATURE_UNDEFINED.equals(s)) {
+            return UnDefType.UNDEF;
+        }
+        int temperature = Integer.parseInt(s);
+        return new QuantityType<>(temperature, SIUnits.CELSIUS);
+    }
+}
diff --git a/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/ExtendedDeviceStateUtil.java b/bundles/org.openhab.binding.miele/src/main/java/org/openhab/binding/miele/internal/ExtendedDeviceStateUtil.java
deleted file mode 100644 (file)
index dfe1fd0..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/**
- * Copyright (c) 2010-2021 Contributors to the openHAB project
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- */
-package org.openhab.binding.miele.internal;
-
-import java.nio.charset.StandardCharsets;
-
-import org.openhab.core.library.types.QuantityType;
-import org.openhab.core.library.unit.SIUnits;
-import org.openhab.core.types.State;
-import org.openhab.core.types.UnDefType;
-
-/**
- * The {@link ExtendedDeviceStateUtil} class contains utility methods for parsing
- * ExtendedDeviceState information
- *
- * @author Jacob Laursen - Added power/water consumption channels
- */
-public class ExtendedDeviceStateUtil {
-    private static final byte[] HEX_ARRAY = "0123456789ABCDEF".getBytes(StandardCharsets.US_ASCII);
-    private static final String TEMPERATURE_UNDEFINED = "32768";
-
-    /**
-     * Convert byte array to hex representation.
-     */
-    public static String bytesToHex(byte[] bytes) {
-        byte[] hexChars = new byte[bytes.length * 2];
-        for (int j = 0; j < bytes.length; j++) {
-            int v = bytes[j] & 0xFF;
-            hexChars[j * 2] = HEX_ARRAY[v >>> 4];
-            hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
-        }
-
-        return new String(hexChars, StandardCharsets.UTF_8);
-    }
-
-    /**
-     * Convert string consisting of 8 bit characters to byte array.
-     * Note: This simple operation has been extracted and put here to document
-     * and ensure correct behavior for 8 bit characters that should be turned
-     * into single bytes without any UTF-8 encoding.
-     */
-    public static byte[] stringToBytes(String input) {
-        return input.getBytes(StandardCharsets.ISO_8859_1);
-    }
-
-    /**
-     * Convert string to Number:Temperature state with unit Celcius
-     */
-    public static State getTemperatureState(String s) throws NumberFormatException {
-        if (TEMPERATURE_UNDEFINED.equals(s)) {
-            return UnDefType.UNDEF;
-        }
-        int temperature = Integer.parseInt(s);
-        return new QuantityType<>(temperature, SIUnits.CELSIUS);
-    }
-}
index 2ecfd854f4ee61f95a0908f7dfd66459d29337dd..4d896fd195ed150a421c238d10b8b514a1cf1324 100644 (file)
@@ -16,7 +16,7 @@ package org.openhab.binding.miele.internal;
  * The {@link FullyQualifiedApplianceIdentifier} class represents a fully qualified appliance identifier.
  * Example: "hdm:ZigBee:0123456789abcdef#210"
  *
- * @author Jacob Laursen - Fixed multicast and protocol support (ZigBee/LAN)
+ * @author Jacob Laursen - Initial contribution
  */
 public class FullyQualifiedApplianceIdentifier {
     private String uid;
index d286209118f7686f476cb2647e9d71a84f246d7c..0ac74412f827b1172f1920a043136ed883582de7 100644 (file)
@@ -28,8 +28,10 @@ public class MieleBindingConstants {
 
     public static final String BINDING_ID = "miele";
     public static final String APPLIANCE_ID = "uid";
-    public static final String DEVICE_CLASS = "dc";
-    public static final String PROTOCOL_PROPERTY_NAME = "protocol";
+    public static final String DEVICE_CLASS = "deviceClass";
+    public static final String MODEL_PROPERTY_NAME = "model";
+    public static final String PROTOCOL_ADAPTER_PROPERTY_NAME = "protocolAdapter";
+    public static final String CONNECTION_TYPE_PROPERTY_NAME = "connectionType";
 
     // JSON-RPC property names
     public static final String SERIAL_NUMBER_PROPERTY_NAME = "serialNumber";
@@ -65,8 +67,14 @@ public class MieleBindingConstants {
 
     // Miele devices classes
     public static final String MIELE_DEVICE_CLASS_COFFEE_SYSTEM = "CoffeeSystem";
+    public static final String MIELE_DEVICE_CLASS_DISHWASHER = "Dishwasher";
     public static final String MIELE_DEVICE_CLASS_FRIDGE = "Fridge";
     public static final String MIELE_DEVICE_CLASS_FRIDGE_FREEZER = "FridgeFreezer";
+    public static final String MIELE_DEVICE_CLASS_HOB = "Hob";
+    public static final String MIELE_DEVICE_CLASS_HOOD = "Hood";
+    public static final String MIELE_DEVICE_CLASS_OVEN = "Oven";
+    public static final String MIELE_DEVICE_CLASS_TUMBLE_DRYER = "TumbleDryer";
+    public static final String MIELE_DEVICE_CLASS_WASHING_MACHINE = "WashingMachine";
 
     // Miele appliance states
     public static final int STATE_UNKNOWN = 0;
index e604686cbe4b5644864a805620e799574f527652..5c0de6e09951a63a6e593ac3936b4d493f67241a 100644 (file)
@@ -35,8 +35,6 @@ import org.openhab.core.thing.ThingUID;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.gson.JsonElement;
-
 /**
  * The {@link MieleApplianceDiscoveryService} tracks appliances that are
  * associated with the Miele@Home gateway
@@ -47,9 +45,6 @@ import com.google.gson.JsonElement;
  */
 public class MieleApplianceDiscoveryService extends AbstractDiscoveryService implements ApplianceStatusListener {
 
-    private static final String MIELE_APPLIANCE_CLASS = "com.miele.xgw3000.gateway.hdm.deviceclasses.MieleAppliance";
-    private static final String MIELE_CLASS = "com.miele.xgw3000.gateway.hdm.deviceclasses.Miele";
-
     private final Logger logger = LoggerFactory.getLogger(MieleApplianceDiscoveryService.class);
 
     private static final int SEARCH_TIME = 60;
@@ -104,16 +99,17 @@ public class MieleApplianceDiscoveryService extends AbstractDiscoveryService imp
             Map<String, Object> properties = new HashMap<>(2);
 
             FullyQualifiedApplianceIdentifier applianceIdentifier = appliance.getApplianceIdentifier();
-            properties.put(PROTOCOL_PROPERTY_NAME, applianceIdentifier.getProtocol());
+            properties.put(MODEL_PROPERTY_NAME, appliance.getApplianceModel());
+            String deviceClass = appliance.getDeviceClass();
+            if (deviceClass != null) {
+                properties.put(DEVICE_CLASS, deviceClass);
+            }
+            properties.put(PROTOCOL_ADAPTER_PROPERTY_NAME, appliance.ProtocolAdapterName);
             properties.put(APPLIANCE_ID, applianceIdentifier.getApplianceId());
             properties.put(SERIAL_NUMBER_PROPERTY_NAME, appliance.getSerialNumber());
-
-            for (JsonElement dc : appliance.DeviceClasses) {
-                String dcStr = dc.getAsString();
-                if (dcStr.contains(MIELE_CLASS) && !dcStr.equals(MIELE_APPLIANCE_CLASS)) {
-                    properties.put(DEVICE_CLASS, dcStr.substring(MIELE_CLASS.length()));
-                    break;
-                }
+            String connectionType = appliance.getConnectionType();
+            if (connectionType != null) {
+                properties.put(CONNECTION_TYPE_PROPERTY_NAME, connectionType);
             }
 
             DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withProperties(properties)
@@ -146,22 +142,9 @@ public class MieleApplianceDiscoveryService extends AbstractDiscoveryService imp
         // nothing to do
     }
 
-    @Override
-    public void onAppliancePropertyChanged(String serialNumber, DeviceProperty dp) {
-        // nothing to do
-    }
-
     private ThingUID getThingUID(HomeDevice appliance) {
         ThingUID bridgeUID = mieleBridgeHandler.getThing().getUID();
-        String modelId = null;
-
-        for (JsonElement dc : appliance.DeviceClasses) {
-            String dcStr = dc.getAsString();
-            if (dcStr.contains(MIELE_CLASS) && !dcStr.equals(MIELE_APPLIANCE_CLASS)) {
-                modelId = dcStr.substring(MIELE_CLASS.length());
-                break;
-            }
-        }
+        String modelId = appliance.getDeviceClass();
 
         if (modelId != null) {
             ThingTypeUID thingTypeUID = getThingTypeUidFromModelId(modelId);
@@ -183,7 +166,7 @@ public class MieleApplianceDiscoveryService extends AbstractDiscoveryService imp
          * coffeemachine. At least until it is known if any models are actually reported
          * as CoffeeMachine, we need this special mapping.
          */
-        if (modelId.equals(MIELE_DEVICE_CLASS_COFFEE_SYSTEM)) {
+        if (MIELE_DEVICE_CLASS_COFFEE_SYSTEM.equals(modelId)) {
             return THING_TYPE_COFFEEMACHINE;
         }
 
index eef48f6b0222fa172b1842865e6fb10959e80c36..729065323c8ca1efdbe8717c3d061d3134b80187 100644 (file)
@@ -26,7 +26,6 @@ import org.openhab.binding.miele.internal.MieleBindingConstants;
 import org.openhab.core.config.discovery.DiscoveryResult;
 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
 import org.openhab.core.config.discovery.mdns.MDNSDiscoveryParticipant;
-import org.openhab.core.config.discovery.mdns.internal.MDNSDiscoveryService;
 import org.openhab.core.thing.ThingTypeUID;
 import org.openhab.core.thing.ThingUID;
 import org.osgi.service.component.annotations.Component;
index 9573812405df5728705ba71af653897740fc2a19..f11db64965dbea45f5f267f8265acac9e3396c30 100644 (file)
@@ -43,14 +43,6 @@ public interface ApplianceStatusListener {
      */
     void onAppliancePropertyChanged(FullyQualifiedApplianceIdentifier applianceIdentifier, DeviceProperty dp);
 
-    /**
-     * This method is called whenever a "property" of the given appliance has changed.
-     *
-     * @param serialNumber The serial number of the appliance that has changed
-     * @param dco the POJO containing the new state of the property
-     */
-    void onAppliancePropertyChanged(String serialNumber, DeviceProperty dp);
-
     /**
      * This method is called whenever an appliance is removed.
      *
index c88a70863654f53c4e1425588f0e407e1ca51fa3..bde856833f8b1adcc08269b8379447ad3ffaefb0 100644 (file)
@@ -42,8 +42,6 @@ public enum CoffeeMachineChannelSelector implements ApplianceChannelSelector {
 
     PRODUCT_TYPE("productTypeId", "productType", StringType.class, true),
     DEVICE_TYPE("mieleDeviceType", "deviceType", StringType.class, true),
-    BRAND_ID("brandId", "brandId", StringType.class, true),
-    COMPANY_ID("companyId", "companyId", StringType.class, true),
     STATE_TEXT(STATE_PROPERTY_NAME, STATE_TEXT_CHANNEL_ID, StringType.class, false),
     STATE(null, STATE_CHANNEL_ID, DecimalType.class, false),
     PROGRAM_TEXT(PROGRAM_ID_PROPERTY_NAME, PROGRAM_TEXT_CHANNEL_ID, StringType.class, false) {
@@ -88,9 +86,9 @@ public enum CoffeeMachineChannelSelector implements ApplianceChannelSelector {
 
     private final Logger logger = LoggerFactory.getLogger(CoffeeMachineChannelSelector.class);
 
-    private final static Map<String, String> programs = Collections.<String, String> emptyMap();
+    private static final Map<String, String> programs = Collections.<String, String> emptyMap();
 
-    private final static Map<String, String> phases = Collections.<String, String> emptyMap();
+    private static final Map<String, String> phases = Collections.<String, String> emptyMap();
 
     private final String mieleID;
     private final String channelID;
index 2b5083d36212022db9c595eb963a49c7010294a3..cff9f134c5cc7fcd0a7b609f4012361e3142c1b6 100644 (file)
@@ -14,9 +14,7 @@ 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 static org.openhab.binding.miele.internal.MieleBindingConstants.PROTOCOL_PROPERTY_NAME;
 
-import org.openhab.binding.miele.internal.FullyQualifiedApplianceIdentifier;
 import org.openhab.core.library.types.OnOffType;
 import org.openhab.core.thing.ChannelUID;
 import org.openhab.core.thing.Thing;
@@ -49,8 +47,6 @@ public class CoffeeMachineHandler extends MieleApplianceHandler<CoffeeMachineCha
 
         String channelID = channelUID.getId();
         String applianceId = (String) getThing().getConfiguration().getProperties().get(APPLIANCE_ID);
-        String protocol = getThing().getProperties().get(PROTOCOL_PROPERTY_NAME);
-        var applianceIdentifier = new FullyQualifiedApplianceIdentifier(applianceId, protocol);
 
         CoffeeMachineChannelSelector selector = (CoffeeMachineChannelSelector) getValueSelectorFromChannelID(channelID);
         JsonElement result = null;
@@ -60,9 +56,9 @@ public class CoffeeMachineHandler extends MieleApplianceHandler<CoffeeMachineCha
                 switch (selector) {
                     case SWITCH: {
                         if (command.equals(OnOffType.ON)) {
-                            result = bridgeHandler.invokeOperation(applianceIdentifier, modelID, "switchOn");
+                            result = bridgeHandler.invokeOperation(applianceId, modelID, "switchOn");
                         } else if (command.equals(OnOffType.OFF)) {
-                            result = bridgeHandler.invokeOperation(applianceIdentifier, modelID, "switchOff");
+                            result = bridgeHandler.invokeOperation(applianceId, modelID, "switchOff");
                         }
                         break;
                     }
@@ -75,7 +71,7 @@ public class CoffeeMachineHandler extends MieleApplianceHandler<CoffeeMachineCha
                 }
             }
             // process result
-            if (isResultProcessable(result)) {
+            if (result != null && isResultProcessable(result)) {
                 logger.debug("Result of operation is {}", result.getAsString());
             }
         } catch (IllegalArgumentException e) {
index de0d8d61de711f4bcad6145c59d9cd3a86174f15..d1281f43b82db5b0813a4eaa6d2ba6b8b94e222e 100644 (file)
 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.PROTOCOL_PROPERTY_NAME;
 import static org.openhab.binding.miele.internal.MieleBindingConstants.WATER_CONSUMPTION_CHANNEL_ID;
 
 import java.math.BigDecimal;
 
-import org.openhab.binding.miele.internal.FullyQualifiedApplianceIdentifier;
 import org.openhab.core.library.types.OnOffType;
 import org.openhab.core.library.types.QuantityType;
 import org.openhab.core.library.unit.Units;
@@ -51,7 +50,7 @@ public class DishWasherHandler extends MieleApplianceHandler<DishwasherChannelSe
     private final Logger logger = LoggerFactory.getLogger(DishWasherHandler.class);
 
     public DishWasherHandler(Thing thing) {
-        super(thing, DishwasherChannelSelector.class, "Dishwasher");
+        super(thing, DishwasherChannelSelector.class, MIELE_DEVICE_CLASS_DISHWASHER);
     }
 
     @Override
@@ -60,8 +59,6 @@ public class DishWasherHandler extends MieleApplianceHandler<DishwasherChannelSe
 
         String channelID = channelUID.getId();
         String applianceId = (String) getThing().getConfiguration().getProperties().get(APPLIANCE_ID);
-        String protocol = getThing().getProperties().get(PROTOCOL_PROPERTY_NAME);
-        var applianceIdentifier = new FullyQualifiedApplianceIdentifier(applianceId, protocol);
 
         DishwasherChannelSelector selector = (DishwasherChannelSelector) getValueSelectorFromChannelID(channelID);
         JsonElement result = null;
@@ -71,9 +68,9 @@ public class DishWasherHandler extends MieleApplianceHandler<DishwasherChannelSe
                 switch (selector) {
                     case SWITCH: {
                         if (command.equals(OnOffType.ON)) {
-                            result = bridgeHandler.invokeOperation(applianceIdentifier, modelID, "start");
+                            result = bridgeHandler.invokeOperation(applianceId, modelID, "start");
                         } else if (command.equals(OnOffType.OFF)) {
-                            result = bridgeHandler.invokeOperation(applianceIdentifier, modelID, "stop");
+                            result = bridgeHandler.invokeOperation(applianceId, modelID, "stop");
                         }
                         break;
                     }
@@ -86,7 +83,7 @@ public class DishWasherHandler extends MieleApplianceHandler<DishwasherChannelSe
                 }
             }
             // process result
-            if (isResultProcessable(result)) {
+            if (result != null && isResultProcessable(result)) {
                 logger.debug("Result of operation is {}", result.getAsString());
             }
         } catch (IllegalArgumentException e) {
index e9ab69139d1e495bb27e4f4e73af7929f6bd8bb7..c00f7fac593f15b19de55c52f5d2afc6644a4504 100644 (file)
@@ -48,8 +48,6 @@ public enum DishwasherChannelSelector implements ApplianceChannelSelector {
 
     PRODUCT_TYPE("productTypeId", "productType", StringType.class, true, false),
     DEVICE_TYPE("mieleDeviceType", "deviceType", StringType.class, true, false),
-    BRAND_ID("brandId", "brandId", StringType.class, true, false),
-    COMPANY_ID("companyId", "companyId", StringType.class, true, false),
     STATE_TEXT(STATE_PROPERTY_NAME, STATE_TEXT_CHANNEL_ID, StringType.class, false, false),
     STATE(null, STATE_CHANNEL_ID, DecimalType.class, false, false),
     PROGRAM_TEXT(PROGRAM_ID_PROPERTY_NAME, PROGRAM_TEXT_CHANNEL_ID, StringType.class, false, false) {
@@ -152,12 +150,12 @@ public enum DishwasherChannelSelector implements ApplianceChannelSelector {
 
     private final Logger logger = LoggerFactory.getLogger(DishwasherChannelSelector.class);
 
-    private final static Map<String, String> programs = Map.ofEntries(entry("26", "Pots & Pans"),
+    private static final Map<String, String> programs = Map.ofEntries(entry("26", "Pots & Pans"),
             entry("27", "Clean Machine"), entry("28", "Economy"), entry("30", "Normal"), entry("32", "Sensor Wash"),
             entry("34", "Energy Saver"), entry("35", "China & Crystal"), entry("36", "Extra Quiet"),
             entry("37", "SaniWash"), entry("38", "QuickPowerWash"), entry("42", "Tall items"));
 
-    private final static Map<String, String> phases = Map.ofEntries(entry("2", "Pre-Wash"), entry("3", "Main Wash"),
+    private static final Map<String, String> phases = Map.ofEntries(entry("2", "Pre-Wash"), entry("3", "Main Wash"),
             entry("4", "Rinses"), entry("6", "Final rinse"), entry("7", "Drying"), entry("8", "Finished"));
 
     private final String mieleID;
index 469e3a92582d7322fb34b9868547415f1ac4563e..c97cffd0fc5275dc1ee8dba7afa6a0c121c13600 100644 (file)
@@ -17,7 +17,7 @@ import static org.openhab.binding.miele.internal.MieleBindingConstants.*;
 import java.lang.reflect.Method;
 import java.util.Map.Entry;
 
-import org.openhab.binding.miele.internal.ExtendedDeviceStateUtil;
+import org.openhab.binding.miele.internal.DeviceUtil;
 import org.openhab.binding.miele.internal.handler.MieleBridgeHandler.DeviceMetaData;
 import org.openhab.core.library.types.DecimalType;
 import org.openhab.core.library.types.OnOffType;
@@ -42,8 +42,6 @@ public enum FridgeChannelSelector implements ApplianceChannelSelector {
 
     PRODUCT_TYPE("productTypeId", "productType", StringType.class, true),
     DEVICE_TYPE("mieleDeviceType", "deviceType", StringType.class, true),
-    BRAND_ID("brandId", "brandId", StringType.class, true),
-    COMPANY_ID("companyId", "companyId", StringType.class, true),
     STATE_TEXT(STATE_PROPERTY_NAME, STATE_TEXT_CHANNEL_ID, StringType.class, false),
     STATE(null, STATE_CHANNEL_ID, DecimalType.class, false),
     SUPERCOOL(null, SUPERCOOL_CHANNEL_ID, OnOffType.class, false),
@@ -148,7 +146,7 @@ public enum FridgeChannelSelector implements ApplianceChannelSelector {
 
     public State getTemperatureState(String s) {
         try {
-            return ExtendedDeviceStateUtil.getTemperatureState(s);
+            return DeviceUtil.getTemperatureState(s);
         } catch (NumberFormatException e) {
             logger.warn("An exception occurred while converting '{}' into a State", s);
             return UnDefType.UNDEF;
index baed695db30a69cd6fa71ecda79d19ea469f0e8b..14d332dc0a1dcc1e768454542d251eea82bd7511 100644 (file)
@@ -17,7 +17,7 @@ import static org.openhab.binding.miele.internal.MieleBindingConstants.*;
 import java.lang.reflect.Method;
 import java.util.Map.Entry;
 
-import org.openhab.binding.miele.internal.ExtendedDeviceStateUtil;
+import org.openhab.binding.miele.internal.DeviceUtil;
 import org.openhab.binding.miele.internal.handler.MieleBridgeHandler.DeviceMetaData;
 import org.openhab.core.library.types.DecimalType;
 import org.openhab.core.library.types.OnOffType;
@@ -43,8 +43,6 @@ public enum FridgeFreezerChannelSelector implements ApplianceChannelSelector {
 
     PRODUCT_TYPE("productTypeId", "productType", StringType.class, true),
     DEVICE_TYPE("mieleDeviceType", "deviceType", StringType.class, true),
-    BRAND_ID("brandId", "brandId", StringType.class, true),
-    COMPANY_ID("companyId", "companyId", StringType.class, true),
     STATE_TEXT(STATE_PROPERTY_NAME, STATE_TEXT_CHANNEL_ID, StringType.class, false),
     STATE(null, STATE_CHANNEL_ID, DecimalType.class, false),
     FREEZERSTATE("freezerState", "freezerstate", StringType.class, false),
@@ -165,7 +163,7 @@ public enum FridgeFreezerChannelSelector implements ApplianceChannelSelector {
 
     public State getTemperatureState(String s) {
         try {
-            return ExtendedDeviceStateUtil.getTemperatureState(s);
+            return DeviceUtil.getTemperatureState(s);
         } catch (NumberFormatException e) {
             logger.warn("An exception occurred while converting '{}' into a State", s);
             return UnDefType.UNDEF;
index a3f665cb684cc333f59f6b91684bfd0ea6c1359e..be9d5926cfbd199cfca67a98b97bbea69f6c9722 100644 (file)
@@ -14,7 +14,6 @@ package org.openhab.binding.miele.internal.handler;
 
 import static org.openhab.binding.miele.internal.MieleBindingConstants.*;
 
-import org.openhab.binding.miele.internal.FullyQualifiedApplianceIdentifier;
 import org.openhab.binding.miele.internal.handler.MieleBridgeHandler.DeviceProperty;
 import org.openhab.core.library.types.OnOffType;
 import org.openhab.core.thing.ChannelUID;
@@ -48,8 +47,6 @@ public class FridgeFreezerHandler extends MieleApplianceHandler<FridgeFreezerCha
 
         String channelID = channelUID.getId();
         String applianceId = (String) getThing().getConfiguration().getProperties().get(APPLIANCE_ID);
-        String protocol = getThing().getProperties().get(PROTOCOL_PROPERTY_NAME);
-        var applianceIdentifier = new FullyQualifiedApplianceIdentifier(applianceId, protocol);
 
         FridgeFreezerChannelSelector selector = (FridgeFreezerChannelSelector) getValueSelectorFromChannelID(channelID);
         JsonElement result = null;
@@ -59,17 +56,17 @@ public class FridgeFreezerHandler extends MieleApplianceHandler<FridgeFreezerCha
                 switch (selector) {
                     case SUPERCOOL: {
                         if (command.equals(OnOffType.ON)) {
-                            result = bridgeHandler.invokeOperation(applianceIdentifier, modelID, "startSuperCooling");
+                            result = bridgeHandler.invokeOperation(applianceId, modelID, "startSuperCooling");
                         } else if (command.equals(OnOffType.OFF)) {
-                            result = bridgeHandler.invokeOperation(applianceIdentifier, modelID, "stopSuperCooling");
+                            result = bridgeHandler.invokeOperation(applianceId, modelID, "stopSuperCooling");
                         }
                         break;
                     }
                     case SUPERFREEZE: {
                         if (command.equals(OnOffType.ON)) {
-                            result = bridgeHandler.invokeOperation(applianceIdentifier, modelID, "startSuperFreezing");
+                            result = bridgeHandler.invokeOperation(applianceId, modelID, "startSuperFreezing");
                         } else if (command.equals(OnOffType.OFF)) {
-                            result = bridgeHandler.invokeOperation(applianceIdentifier, modelID, "stopSuperFreezing");
+                            result = bridgeHandler.invokeOperation(applianceId, modelID, "stopSuperFreezing");
                         }
                         break;
                     }
@@ -80,7 +77,7 @@ public class FridgeFreezerHandler extends MieleApplianceHandler<FridgeFreezerCha
                 }
             }
             // process result
-            if (isResultProcessable(result)) {
+            if (result != null && isResultProcessable(result)) {
                 logger.debug("Result of operation is {}", result.getAsString());
             }
         } catch (IllegalArgumentException e) {
@@ -94,7 +91,7 @@ public class FridgeFreezerHandler extends MieleApplianceHandler<FridgeFreezerCha
     protected void onAppliancePropertyChanged(DeviceProperty dp) {
         super.onAppliancePropertyChanged(dp);
 
-        if (!dp.Name.equals(STATE_PROPERTY_NAME)) {
+        if (!STATE_PROPERTY_NAME.equals(dp.Name)) {
             return;
         }
 
index 79462a5be3b3e97197148834cef3f6f77fe862e4..84bd5509f88f0fb8d4ed0ec0d81c4373015b723d 100644 (file)
@@ -14,7 +14,6 @@ package org.openhab.binding.miele.internal.handler;
 
 import static org.openhab.binding.miele.internal.MieleBindingConstants.*;
 
-import org.openhab.binding.miele.internal.FullyQualifiedApplianceIdentifier;
 import org.openhab.binding.miele.internal.handler.MieleBridgeHandler.DeviceProperty;
 import org.openhab.core.library.types.OnOffType;
 import org.openhab.core.thing.ChannelUID;
@@ -49,8 +48,6 @@ public class FridgeHandler extends MieleApplianceHandler<FridgeChannelSelector>
 
         String channelID = channelUID.getId();
         String applianceId = (String) getThing().getConfiguration().getProperties().get(APPLIANCE_ID);
-        String protocol = getThing().getProperties().get(PROTOCOL_PROPERTY_NAME);
-        var applianceIdentifier = new FullyQualifiedApplianceIdentifier(applianceId, protocol);
 
         FridgeChannelSelector selector = (FridgeChannelSelector) getValueSelectorFromChannelID(channelID);
         JsonElement result = null;
@@ -60,15 +57,15 @@ public class FridgeHandler extends MieleApplianceHandler<FridgeChannelSelector>
                 switch (selector) {
                     case SUPERCOOL: {
                         if (command.equals(OnOffType.ON)) {
-                            result = bridgeHandler.invokeOperation(applianceIdentifier, modelID, "startSuperCooling");
+                            result = bridgeHandler.invokeOperation(applianceId, modelID, "startSuperCooling");
                         } else if (command.equals(OnOffType.OFF)) {
-                            result = bridgeHandler.invokeOperation(applianceIdentifier, modelID, "stopSuperCooling");
+                            result = bridgeHandler.invokeOperation(applianceId, modelID, "stopSuperCooling");
                         }
                         break;
                     }
                     case START: {
                         if (command.equals(OnOffType.ON)) {
-                            result = bridgeHandler.invokeOperation(applianceIdentifier, modelID, "start");
+                            result = bridgeHandler.invokeOperation(applianceId, modelID, "start");
                         }
                         break;
                     }
@@ -81,7 +78,7 @@ public class FridgeHandler extends MieleApplianceHandler<FridgeChannelSelector>
                 }
             }
             // process result
-            if (isResultProcessable(result)) {
+            if (result != null && isResultProcessable(result)) {
                 logger.debug("Result of operation is {}", result.getAsString());
             }
         } catch (IllegalArgumentException e) {
@@ -95,7 +92,7 @@ public class FridgeHandler extends MieleApplianceHandler<FridgeChannelSelector>
     protected void onAppliancePropertyChanged(DeviceProperty dp) {
         super.onAppliancePropertyChanged(dp);
 
-        if (!dp.Name.equals(STATE_PROPERTY_NAME)) {
+        if (!STATE_PROPERTY_NAME.equals(dp.Name)) {
             return;
         }
 
index a8a3ef2089729e455d7340855b858c93b8fc4132..abe82e7c86d654d5d4e7c1fc4e97e11cc2ce2b9c 100644 (file)
@@ -37,8 +37,6 @@ public enum HobChannelSelector implements ApplianceChannelSelector {
 
     PRODUCT_TYPE("productTypeId", "productType", StringType.class, true),
     DEVICE_TYPE("mieleDeviceType", "deviceType", StringType.class, true),
-    BRAND_ID("brandId", "brandId", StringType.class, true),
-    COMPANY_ID("companyId", "companyId", StringType.class, true),
     STATE_TEXT(STATE_PROPERTY_NAME, STATE_TEXT_CHANNEL_ID, StringType.class, false),
     STATE(null, STATE_CHANNEL_ID, DecimalType.class, false),
     PLATES("plateNumbers", "plates", DecimalType.class, true),
index 538421b253dcc4fa3270672b168bc16e30fcf847..bbbde6f630030153ca730edf880e28f03d9f8c09 100644 (file)
@@ -12,6 +12,8 @@
  */
 package org.openhab.binding.miele.internal.handler;
 
+import static org.openhab.binding.miele.internal.MieleBindingConstants.MIELE_DEVICE_CLASS_HOB;
+
 import org.openhab.core.thing.ChannelUID;
 import org.openhab.core.thing.Thing;
 import org.openhab.core.types.Command;
@@ -26,7 +28,7 @@ import org.openhab.core.types.Command;
 public class HobHandler extends MieleApplianceHandler<HobChannelSelector> {
 
     public HobHandler(Thing thing) {
-        super(thing, HobChannelSelector.class, "Hob");
+        super(thing, HobChannelSelector.class, MIELE_DEVICE_CLASS_HOB);
     }
 
     @Override
index bdedbf2a3f01368a8ec917e5f22767c532e4bf02..623c9830d335cb799c746fbd9c7d8d3716f53063 100644 (file)
@@ -39,8 +39,6 @@ public enum HoodChannelSelector implements ApplianceChannelSelector {
 
     PRODUCT_TYPE("productTypeId", "productType", StringType.class, true),
     DEVICE_TYPE("mieleDeviceType", "deviceType", StringType.class, true),
-    BRAND_ID("brandId", "brandId", StringType.class, true),
-    COMPANY_ID("companyId", "companyId", StringType.class, true),
     STATE_TEXT(STATE_PROPERTY_NAME, STATE_TEXT_CHANNEL_ID, StringType.class, false),
     STATE(null, STATE_CHANNEL_ID, DecimalType.class, false),
     VENTILATION("ventilationPower", "ventilation", DecimalType.class, false),
index f89c11d0db57728ce906a3086f95a2db637e447f..2211e0d26c848b8d4918c8039cd466e56d16eb20 100644 (file)
@@ -13,9 +13,8 @@
 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.PROTOCOL_PROPERTY_NAME;
+import static org.openhab.binding.miele.internal.MieleBindingConstants.MIELE_DEVICE_CLASS_HOOD;
 
-import org.openhab.binding.miele.internal.FullyQualifiedApplianceIdentifier;
 import org.openhab.core.library.types.OnOffType;
 import org.openhab.core.thing.ChannelUID;
 import org.openhab.core.thing.Thing;
@@ -39,7 +38,7 @@ public class HoodHandler extends MieleApplianceHandler<HoodChannelSelector> {
     private final Logger logger = LoggerFactory.getLogger(HoodHandler.class);
 
     public HoodHandler(Thing thing) {
-        super(thing, HoodChannelSelector.class, "Hood");
+        super(thing, HoodChannelSelector.class, MIELE_DEVICE_CLASS_HOOD);
     }
 
     @Override
@@ -48,8 +47,6 @@ public class HoodHandler extends MieleApplianceHandler<HoodChannelSelector> {
 
         String channelID = channelUID.getId();
         String applianceId = (String) getThing().getConfiguration().getProperties().get(APPLIANCE_ID);
-        String protocol = getThing().getProperties().get(PROTOCOL_PROPERTY_NAME);
-        var applianceIdentifier = new FullyQualifiedApplianceIdentifier(applianceId, protocol);
 
         HoodChannelSelector selector = (HoodChannelSelector) getValueSelectorFromChannelID(channelID);
         JsonElement result = null;
@@ -59,15 +56,15 @@ public class HoodHandler extends MieleApplianceHandler<HoodChannelSelector> {
                 switch (selector) {
                     case LIGHT: {
                         if (command.equals(OnOffType.ON)) {
-                            result = bridgeHandler.invokeOperation(applianceIdentifier, modelID, "startLighting");
+                            result = bridgeHandler.invokeOperation(applianceId, modelID, "startLighting");
                         } else if (command.equals(OnOffType.OFF)) {
-                            result = bridgeHandler.invokeOperation(applianceIdentifier, modelID, "stopLighting");
+                            result = bridgeHandler.invokeOperation(applianceId, modelID, "stopLighting");
                         }
                         break;
                     }
                     case STOP: {
                         if (command.equals(OnOffType.ON)) {
-                            result = bridgeHandler.invokeOperation(applianceIdentifier, modelID, "stop");
+                            result = bridgeHandler.invokeOperation(applianceId, modelID, "stop");
                         }
                         break;
                     }
@@ -78,7 +75,7 @@ public class HoodHandler extends MieleApplianceHandler<HoodChannelSelector> {
                 }
             }
             // process result
-            if (isResultProcessable(result)) {
+            if (result != null && isResultProcessable(result)) {
                 logger.debug("Result of operation is {}", result.getAsString());
             }
         } catch (IllegalArgumentException e) {
index b2a7b70e78b612debccbc649f1648310b5ef6551..9c84e1a912a3e20a9046a7533a088ff5dc165fbe 100644 (file)
@@ -20,8 +20,8 @@ import java.util.Set;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-import org.apache.commons.lang3.StringUtils;
-import org.openhab.binding.miele.internal.ExtendedDeviceStateUtil;
+import org.eclipse.jdt.annotation.NonNull;
+import org.openhab.binding.miele.internal.DeviceUtil;
 import org.openhab.binding.miele.internal.FullyQualifiedApplianceIdentifier;
 import org.openhab.binding.miele.internal.handler.MieleBridgeHandler.DeviceClassObject;
 import org.openhab.binding.miele.internal.handler.MieleBridgeHandler.DeviceMetaData;
@@ -84,8 +84,13 @@ public abstract class MieleApplianceHandler<E extends Enum<E> & ApplianceChannel
 
     public ApplianceChannelSelector getValueSelectorFromChannelID(String valueSelectorText)
             throws IllegalArgumentException {
-        for (ApplianceChannelSelector c : selectorType.getEnumConstants()) {
-            if (c.getChannelID() != null && c.getChannelID().equals(valueSelectorText)) {
+        E[] enumConstants = selectorType.getEnumConstants();
+        if (enumConstants == null) {
+            throw new IllegalArgumentException(
+                    String.format("Could not get enum constants for value selector: %s", valueSelectorText));
+        }
+        for (ApplianceChannelSelector c : enumConstants) {
+            if (c != null && c.getChannelID() != null && c.getChannelID().equals(valueSelectorText)) {
                 return c;
             }
         }
@@ -95,8 +100,13 @@ public abstract class MieleApplianceHandler<E extends Enum<E> & ApplianceChannel
 
     public ApplianceChannelSelector getValueSelectorFromMieleID(String valueSelectorText)
             throws IllegalArgumentException {
-        for (ApplianceChannelSelector c : selectorType.getEnumConstants()) {
-            if (c.getMieleID() != null && c.getMieleID().equals(valueSelectorText)) {
+        E[] enumConstants = selectorType.getEnumConstants();
+        if (enumConstants == null) {
+            throw new IllegalArgumentException(
+                    String.format("Could not get enum constants for value selector: %s", valueSelectorText));
+        }
+        for (ApplianceChannelSelector c : enumConstants) {
+            if (c != null && c.getMieleID() != null && c.getMieleID().equals(valueSelectorText)) {
                 return c;
             }
         }
@@ -110,16 +120,14 @@ public abstract class MieleApplianceHandler<E extends Enum<E> & ApplianceChannel
         final String applianceId = (String) getThing().getConfiguration().getProperties().get(APPLIANCE_ID);
         if (applianceId != null) {
             this.applianceId = applianceId;
-            if (getMieleBridgeHandler() != null) {
-                ThingStatusInfo statusInfo = getBridge().getStatusInfo();
-                updateStatus(statusInfo.getStatus(), statusInfo.getStatusDetail(), statusInfo.getDescription());
-            }
+            this.onBridgeConnectionResumed();
         }
     }
 
     public void onBridgeConnectionResumed() {
-        if (getMieleBridgeHandler() != null) {
-            ThingStatusInfo statusInfo = getBridge().getStatusInfo();
+        Bridge bridge = getBridge();
+        if (bridge != null && getMieleBridgeHandler() != null) {
+            ThingStatusInfo statusInfo = bridge.getStatusInfo();
             updateStatus(statusInfo.getStatus(), statusInfo.getStatusDetail(), statusInfo.getDescription());
         }
     }
@@ -149,43 +157,32 @@ public abstract class MieleApplianceHandler<E extends Enum<E> & ApplianceChannel
     public void onApplianceStateChanged(FullyQualifiedApplianceIdentifier applicationIdentifier,
             DeviceClassObject dco) {
         String myApplianceId = (String) getThing().getConfiguration().getProperties().get(APPLIANCE_ID);
-        String modelID = StringUtils.right(dco.DeviceClass,
-                dco.DeviceClass.length() - new String("com.miele.xgw3000.gateway.hdm.deviceclasses.Miele").length());
-
-        if (myApplianceId.equals(applicationIdentifier.getApplianceId())) {
-            if (modelID.equals(this.modelID)) {
-                for (JsonElement prop : dco.Properties.getAsJsonArray()) {
-                    try {
-                        DeviceProperty dp = gson.fromJson(prop, DeviceProperty.class);
-                        if (!dp.Name.equals(EXTENDED_DEVICE_STATE_PROPERTY_NAME)) {
-                            dp.Value = StringUtils.trim(dp.Value);
-                            dp.Value = StringUtils.strip(dp.Value);
-                        }
-
-                        onAppliancePropertyChanged(applicationIdentifier, dp);
-                    } catch (Exception p) {
-                        // Ignore - this is due to an unrecognized and not yet reverse-engineered array property
-                    }
-                }
-            }
-        }
-    }
-
-    @Override
-    public void onAppliancePropertyChanged(String serialNumber, DeviceProperty dp) {
-        String mySerialNumber = getThing().getProperties().get(SERIAL_NUMBER_PROPERTY_NAME);
-        if (!mySerialNumber.equals(serialNumber)) {
+        if (myApplianceId == null || !myApplianceId.equals(applicationIdentifier.getApplianceId())) {
             return;
         }
 
-        this.onAppliancePropertyChanged(dp);
+        for (JsonElement prop : dco.Properties.getAsJsonArray()) {
+            try {
+                DeviceProperty dp = gson.fromJson(prop, DeviceProperty.class);
+                if (dp == null) {
+                    continue;
+                }
+                if (!EXTENDED_DEVICE_STATE_PROPERTY_NAME.equals(dp.Name)) {
+                    dp.Value = dp.Value.trim();
+                    dp.Value = dp.Value.strip();
+                }
+                onAppliancePropertyChanged(applicationIdentifier, 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 myApplianceId = (String) getThing().getConfiguration().getProperties().get(APPLIANCE_ID);
 
-        if (!myApplianceId.equals(applicationIdentifier.getApplianceId())) {
+        if (myApplianceId == null || !myApplianceId.equals(applicationIdentifier.getApplianceId())) {
             return;
         }
 
@@ -202,14 +199,16 @@ public abstract class MieleApplianceHandler<E extends Enum<E> & ApplianceChannel
                     dmd = gson.fromJson(jsonMetaData, DeviceMetaData.class);
                     // only keep the enum, if any - that's all we care for events we receive via multicast
                     // all other fields are nulled
-                    dmd.LocalizedID = null;
-                    dmd.LocalizedValue = null;
-                    dmd.Filter = null;
-                    dmd.description = null;
+                    if (dmd != null) {
+                        dmd.LocalizedID = null;
+                        dmd.LocalizedValue = null;
+                        dmd.Filter = null;
+                        dmd.description = null;
+                    }
                 }
             }
             if (dp.Metadata != null) {
-                String metadata = StringUtils.replace(dp.Metadata.toString(), "enum", "MieleEnum");
+                String metadata = dp.Metadata.toString().replace("enum", "MieleEnum");
                 JsonObject jsonMetaData = (JsonObject) JsonParser.parseString(metadata);
                 dmd = gson.fromJson(jsonMetaData, DeviceMetaData.class);
                 metaDataCache.put(new StringBuilder().append(dp.Name).toString().trim(), metadata);
@@ -217,9 +216,9 @@ public abstract class MieleApplianceHandler<E extends Enum<E> & ApplianceChannel
 
             if (dp.Name.equals(EXTENDED_DEVICE_STATE_PROPERTY_NAME)) {
                 if (!dp.Value.isEmpty()) {
-                    byte[] extendedStateBytes = ExtendedDeviceStateUtil.stringToBytes(dp.Value);
+                    byte[] extendedStateBytes = DeviceUtil.stringToBytes(dp.Value);
                     logger.trace("Extended device state for {}: {}", getThing().getUID(),
-                            ExtendedDeviceStateUtil.bytesToHex(extendedStateBytes));
+                            DeviceUtil.bytesToHex(extendedStateBytes));
                     if (this instanceof ExtendedDeviceStateListener) {
                         ((ExtendedDeviceStateListener) this).onApplianceExtendedStateChanged(extendedStateBytes);
                     }
@@ -234,7 +233,7 @@ public abstract class MieleApplianceHandler<E extends Enum<E> & ApplianceChannel
                 logger.trace("{} is not a valid channel for a {}", dp.Name, modelID);
             }
 
-            String dpValue = StringUtils.trim(StringUtils.strip(dp.Value));
+            String dpValue = dp.Value.strip().trim();
 
             if (selector != null) {
                 if (!selector.isProperty()) {
@@ -248,10 +247,11 @@ public abstract class MieleApplianceHandler<E extends Enum<E> & ApplianceChannel
                     } else {
                         updateState(theChannelUID, UnDefType.UNDEF);
                     }
-                } else if (dpValue != null) {
+                } else {
                     logger.debug("Updating the property '{}' of '{}' to '{}'", selector.getChannelID(),
                             getThing().getUID(), selector.getState(dpValue, dmd).toString());
-                    Map<String, String> properties = editProperties();
+                    @NonNull
+                    Map<@NonNull String, @NonNull String> properties = editProperties();
                     properties.put(selector.getChannelID(), selector.getState(dpValue, dmd).toString());
                     updateProperties(properties);
                 }
@@ -317,9 +317,19 @@ public abstract class MieleApplianceHandler<E extends Enum<E> & ApplianceChannel
         FullyQualifiedApplianceIdentifier applianceIdentifier = appliance.getApplianceIdentifier();
 
         if (applianceId.equals(applianceIdentifier.getApplianceId())) {
-            Map<String, String> properties = editProperties();
-            properties.put(PROTOCOL_PROPERTY_NAME, applianceIdentifier.getProtocol());
+            @NonNull
+            Map<@NonNull String, @NonNull String> properties = editProperties();
+            properties.put(MODEL_PROPERTY_NAME, appliance.getApplianceModel());
+            String deviceClass = appliance.getDeviceClass();
+            if (deviceClass != null) {
+                properties.put(DEVICE_CLASS, deviceClass);
+            }
+            properties.put(PROTOCOL_ADAPTER_PROPERTY_NAME, appliance.ProtocolAdapterName);
             properties.put(SERIAL_NUMBER_PROPERTY_NAME, appliance.getSerialNumber());
+            String connectionType = appliance.getConnectionType();
+            if (connectionType != null) {
+                properties.put(CONNECTION_TYPE_PROPERTY_NAME, connectionType);
+            }
             updateProperties(properties);
             updateStatus(ThingStatus.ONLINE);
         }
@@ -343,6 +353,9 @@ public abstract class MieleApplianceHandler<E extends Enum<E> & ApplianceChannel
     }
 
     protected boolean isResultProcessable(JsonElement result) {
-        return result != null && !result.isJsonNull();
+        if (result == null) {
+            throw new IllegalArgumentException("Provided result is null");
+        }
+        return !result.isJsonNull();
     }
 }
index 9f88b5f0075c47876327b114bb3169ebcde5f3c6..78ea4e8bc6233246ab1838c225da276fc9c6f338 100644 (file)
@@ -31,10 +31,13 @@ import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 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;
@@ -44,7 +47,7 @@ import java.util.concurrent.TimeUnit;
 import java.util.regex.Pattern;
 import java.util.zip.GZIPInputStream;
 
-import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
 import org.openhab.binding.miele.internal.FullyQualifiedApplianceIdentifier;
 import org.openhab.core.common.NamedThreadFactory;
 import org.openhab.core.thing.Bridge;
@@ -76,7 +79,10 @@ import com.google.gson.JsonParser;
  **/
 public class MieleBridgeHandler extends BaseBridgeHandler {
 
-    public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_XGW3000);
+    @NonNull
+    public static final Set<@NonNull ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_XGW3000);
+
+    private static final String MIELE_CLASS = "com.miele.xgw3000.gateway.hdm.deviceclasses.Miele";
 
     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])$");
@@ -97,7 +103,9 @@ public class MieleBridgeHandler extends BaseBridgeHandler {
     protected ExecutorService executor;
     protected Future<?> eventListenerJob;
 
-    protected List<HomeDevice> previousHomeDevices = new CopyOnWriteArrayList<>();
+    @NonNull
+    protected Map<String, HomeDevice> cachedHomeDevicesByApplianceId = new ConcurrentHashMap<String, HomeDevice>();
+    protected Map<String, HomeDevice> cachedHomeDevicesByRemoteUid = new ConcurrentHashMap<String, HomeDevice>();
 
     protected URL url;
     protected Map<String, String> headers;
@@ -105,6 +113,8 @@ public class MieleBridgeHandler extends BaseBridgeHandler {
     // Data structures to de-JSONify whatever Miele appliances are sending us
     public class HomeDevice {
 
+        private static final String MIELE_APPLIANCE_CLASS = "com.miele.xgw3000.gateway.hdm.deviceclasses.MieleAppliance";
+
         public String Name;
         public String Status;
         public String ParentUID;
@@ -125,9 +135,49 @@ public class MieleBridgeHandler extends BaseBridgeHandler {
             return new FullyQualifiedApplianceIdentifier(this.UID);
         }
 
+        @NonNull
         public String getSerialNumber() {
             return Properties.get("serial.number").getAsString();
         }
+
+        @NonNull
+        public String getRemoteUid() {
+            JsonElement remoteUid = Properties.get("remote.uid");
+            if (remoteUid == null) {
+                // remote.uid and serial.number seems to be the same. If remote.uid
+                // is missing for some reason, it makes sense to provide fallback
+                // to serial number.
+                return getSerialNumber();
+            }
+            return remoteUid.getAsString();
+        }
+
+        public String getConnectionType() {
+            JsonElement connectionType = Properties.get("connection.type");
+            if (connectionType == null) {
+                return null;
+            }
+            return connectionType.getAsString();
+        }
+
+        @NonNull
+        public String getApplianceModel() {
+            JsonElement model = Properties.get("miele.model");
+            if (model == null) {
+                return "";
+            }
+            return model.getAsString();
+        }
+
+        public String getDeviceClass() {
+            for (JsonElement dc : DeviceClasses) {
+                String dcStr = dc.getAsString();
+                if (dcStr.contains(MIELE_CLASS) && !dcStr.equals(MIELE_APPLIANCE_CLASS)) {
+                    return dcStr.substring(MIELE_CLASS.length());
+                }
+            }
+            return null;
+        }
     }
 
     public class DeviceClassObject {
@@ -206,95 +256,101 @@ public class MieleBridgeHandler extends BaseBridgeHandler {
     private Runnable pollingRunnable = new Runnable() {
         @Override
         public void run() {
-            if (IP_PATTERN.matcher((String) getConfig().get(HOST)).matches()) {
-                try {
-                    if (isReachable((String) getConfig().get(HOST))) {
-                        currentBridgeConnectionState = true;
-                    } else {
-                        currentBridgeConnectionState = false;
-                        lastBridgeConnectionState = false;
-                        onConnectionLost();
+            if (!IP_PATTERN.matcher((String) getConfig().get(HOST)).matches()) {
+                logger.debug("Invalid IP address for the Miele@Home gateway : '{}'", getConfig().get(HOST));
+                return;
+            }
+
+            try {
+                if (isReachable((String) getConfig().get(HOST))) {
+                    currentBridgeConnectionState = true;
+                } else {
+                    currentBridgeConnectionState = false;
+                    lastBridgeConnectionState = false;
+                    onConnectionLost();
+                }
+
+                if (!lastBridgeConnectionState && currentBridgeConnectionState) {
+                    logger.debug("Connection to Miele Gateway {} established.", getConfig().get(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);
+                        }
                     }
+                    cachedHomeDevicesByApplianceId.put(key, hd);
+                    cachedHomeDevicesByRemoteUid.put(hd.getRemoteUid(), hd);
+                }
 
-                    if (!lastBridgeConnectionState && currentBridgeConnectionState) {
-                        logger.debug("Connection to Miele Gateway {} established.", getConfig().get(HOST));
-                        lastBridgeConnectionState = true;
-                        onConnectionResumed();
+                @NonNull
+                Set<@NonNull Entry<String, HomeDevice>> cachedEntries = cachedHomeDevicesByApplianceId.entrySet();
+                @NonNull
+                Iterator<@NonNull 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 (ApplianceStatusListener listener : applianceStatusListeners) {
+                            listener.onApplianceRemoved(cachedHomeDevice);
+                        }
+                        cachedHomeDevicesByRemoteUid.remove(cachedHomeDevice.getRemoteUid());
+                        iterator.remove();
                     }
+                }
 
-                    if (currentBridgeConnectionState) {
-                        if (getThing().getStatus() == ThingStatus.ONLINE) {
-                            List<HomeDevice> currentHomeDevices = getHomeDevices();
-                            for (HomeDevice hd : currentHomeDevices) {
-                                boolean isExisting = false;
-                                for (HomeDevice phd : previousHomeDevices) {
-                                    if (phd.UID.equals(hd.UID)) {
-                                        isExisting = true;
-                                        break;
-                                    }
-                                }
-                                if (!isExisting) {
-                                    logger.debug("A new appliance with ID '{}' has been added", hd.UID);
-                                    for (ApplianceStatusListener listener : applianceStatusListeners) {
-                                        listener.onApplianceAdded(hd);
-                                    }
-                                }
-                            }
+                for (Thing appliance : getThing().getThings()) {
+                    if (appliance.getStatus() == ThingStatus.ONLINE) {
+                        String applianceId = (String) appliance.getConfiguration().getProperties().get(APPLIANCE_ID);
+                        FullyQualifiedApplianceIdentifier applianceIdentifier = getApplianceIdentifierFromApplianceId(
+                                applianceId);
 
-                            for (HomeDevice hd : previousHomeDevices) {
-                                boolean isCurrent = false;
-                                for (HomeDevice chd : currentHomeDevices) {
-                                    if (chd.UID.equals(hd.UID)) {
-                                        isCurrent = true;
-                                        break;
-                                    }
-                                }
-                                if (!isCurrent) {
-                                    logger.debug("The appliance with ID '{}' has been removed", hd);
-                                    for (ApplianceStatusListener listener : applianceStatusListeners) {
-                                        listener.onApplianceRemoved(hd);
+                        if (applianceIdentifier == null) {
+                            logger.error("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);
+
+                        if (result != null) {
+                            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;
                                     }
-                                }
-                            }
 
-                            previousHomeDevices = currentHomeDevices;
-
-                            for (Thing appliance : getThing().getThings()) {
-                                if (appliance.getStatus() == ThingStatus.ONLINE) {
-                                    String applianceId = (String) appliance.getConfiguration().getProperties()
-                                            .get(APPLIANCE_ID);
-                                    String protocol = appliance.getProperties().get(PROTOCOL_PROPERTY_NAME);
-                                    var applianceIdentifier = new FullyQualifiedApplianceIdentifier(applianceId,
-                                            protocol);
-
-                                    Object[] args = new Object[2];
-                                    args[0] = applianceIdentifier.getUid();
-                                    args[1] = true;
-                                    JsonElement result = invokeRPC("HDAccess/getDeviceClassObjects", args);
-
-                                    if (result != null) {
-                                        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());
-                                            }
-                                        }
+                                    for (ApplianceStatusListener listener : applianceStatusListeners) {
+                                        listener.onApplianceStateChanged(applianceIdentifier, dco);
                                     }
+                                } catch (Exception e) {
+                                    logger.debug("An exception occurred while querying an appliance : '{}'",
+                                            e.getMessage());
                                 }
                             }
                         }
                     }
-                } catch (Exception e) {
-                    logger.debug("An exception occurred while polling an appliance :'{}'", e.getMessage());
                 }
-            } else {
-                logger.debug("Invalid IP address for the Miele@Home gateway : '{}'", getConfig().get(HOST));
+            } catch (Exception e) {
+                logger.debug("An exception occurred while polling an appliance :'{}'", e.getMessage());
             }
         }
 
@@ -339,6 +395,15 @@ public class MieleBridgeHandler extends BaseBridgeHandler {
         return devices;
     }
 
+    private FullyQualifiedApplianceIdentifier getApplianceIdentifierFromApplianceId(String applianceId) {
+        HomeDevice homeDevice = this.cachedHomeDevicesByApplianceId.get(applianceId);
+        if (homeDevice == null) {
+            return null;
+        }
+
+        return homeDevice.getApplianceIdentifier();
+    }
+
     private Runnable eventListenerRunnable = () -> {
         if (IP_PATTERN.matcher((String) getConfig().get(INTERFACE)).matches()) {
             while (true) {
@@ -378,16 +443,16 @@ public class MieleBridgeHandler extends BaseBridgeHandler {
                                 DeviceProperty dp = new DeviceProperty();
                                 String id = null;
 
-                                String[] parts = StringUtils.split(event, "&");
+                                String[] parts = event.split("&");
                                 for (String p : parts) {
-                                    String[] subparts = StringUtils.split(p, "=");
+                                    String[] subparts = p.split("=");
                                     switch (subparts[0]) {
                                         case "property": {
                                             dp.Name = subparts[1];
                                             break;
                                         }
                                         case "value": {
-                                            dp.Value = StringUtils.trim(StringUtils.strip(subparts[1]));
+                                            dp.Value = subparts[1].strip().trim();
                                             break;
                                         }
                                         case "id": {
@@ -403,15 +468,19 @@ public class MieleBridgeHandler extends BaseBridgeHandler {
 
                                 // In XGW 3000 firmware 2.03 this was changed from UID (hdm:ZigBee:0123456789abcdef#210)
                                 // to serial number (001234567890)
+                                FullyQualifiedApplianceIdentifier applianceIdentifier;
                                 if (id.startsWith("hdm:")) {
-                                    for (ApplianceStatusListener listener : applianceStatusListeners) {
-                                        listener.onAppliancePropertyChanged(new FullyQualifiedApplianceIdentifier(id),
-                                                dp);
-                                    }
+                                    applianceIdentifier = new FullyQualifiedApplianceIdentifier(id);
                                 } else {
-                                    for (ApplianceStatusListener listener : applianceStatusListeners) {
-                                        listener.onAppliancePropertyChanged(id, dp);
+                                    HomeDevice device = cachedHomeDevicesByRemoteUid.get(id);
+                                    if (device == null) {
+                                        logger.debug("Multicast event not handled as id {} is unknown.", id);
+                                        continue;
                                     }
+                                    applianceIdentifier = device.getApplianceIdentifier();
+                                }
+                                for (ApplianceStatusListener listener : applianceStatusListeners) {
+                                    listener.onAppliancePropertyChanged(applianceIdentifier, dp);
                                 }
                             } catch (SocketTimeoutException e) {
                                 try {
@@ -445,19 +514,27 @@ public class MieleBridgeHandler extends BaseBridgeHandler {
         }
     };
 
-    public JsonElement invokeOperation(FullyQualifiedApplianceIdentifier applianceIdentifier, String modelID,
-            String methodName) {
-        if (getThing().getStatus() == ThingStatus.ONLINE) {
-            Object[] args = new Object[4];
-            args[0] = applianceIdentifier.getUid();
-            args[1] = "com.miele.xgw3000.gateway.hdm.deviceclasses.Miele" + modelID;
-            args[2] = methodName;
-            args[3] = null;
-            return invokeRPC("HDAccess/invokeDCOOperation", args);
-        } else {
+    public JsonElement invokeOperation(String applianceId, String modelID, String methodName) {
+        if (getThing().getStatus() != ThingStatus.ONLINE) {
             logger.debug("The Bridge is offline - operations can not be invoked.");
             return null;
         }
+
+        FullyQualifiedApplianceIdentifier applianceIdentifier = getApplianceIdentifierFromApplianceId(applianceId);
+        if (applianceIdentifier == null) {
+            logger.error(
+                    "The appliance with ID '{}' was not found in appliance list from bridge - operations can not be invoked.",
+                    applianceId);
+            return null;
+        }
+
+        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);
     }
 
     protected JsonElement invokeRPC(String methodName, Object[] args) {
index 7866c2e806118a6eb3641ea617e29d40284ffd96..f6814a8163a9af89ba5b5522f8479eaba2aa329e 100644 (file)
@@ -22,7 +22,7 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.TimeZone;
 
-import org.openhab.binding.miele.internal.ExtendedDeviceStateUtil;
+import org.openhab.binding.miele.internal.DeviceUtil;
 import org.openhab.binding.miele.internal.handler.MieleBridgeHandler.DeviceMetaData;
 import org.openhab.core.library.types.DateTimeType;
 import org.openhab.core.library.types.DecimalType;
@@ -49,8 +49,6 @@ public enum OvenChannelSelector implements ApplianceChannelSelector {
 
     PRODUCT_TYPE("productTypeId", "productType", StringType.class, true),
     DEVICE_TYPE("mieleDeviceType", "deviceType", StringType.class, true),
-    BRAND_ID("brandId", "brandId", StringType.class, true),
-    COMPANY_ID("companyId", "companyId", StringType.class, true),
     STATE_TEXT(STATE_PROPERTY_NAME, STATE_TEXT_CHANNEL_ID, StringType.class, false),
     STATE(null, STATE_CHANNEL_ID, DecimalType.class, false),
     PROGRAM_TEXT(PROGRAM_ID_PROPERTY_NAME, PROGRAM_TEXT_CHANNEL_ID, StringType.class, false),
@@ -167,7 +165,7 @@ public enum OvenChannelSelector implements ApplianceChannelSelector {
 
     private final Logger logger = LoggerFactory.getLogger(OvenChannelSelector.class);
 
-    private final static Map<String, String> phases = Map.ofEntries(entry("1", "Heating"), entry("2", "Temp. hold"),
+    private static final Map<String, String> phases = Map.ofEntries(entry("1", "Heating"), entry("2", "Temp. hold"),
             entry("3", "Door Open"), entry("4", "Pyrolysis"), entry("7", "Lighting"), entry("8", "Searing phase"),
             entry("10", "Defrost"), entry("11", "Cooling down"), entry("12", "Energy save phase"));
 
@@ -241,7 +239,7 @@ public enum OvenChannelSelector implements ApplianceChannelSelector {
 
     public State getTemperatureState(String s) {
         try {
-            return ExtendedDeviceStateUtil.getTemperatureState(s);
+            return DeviceUtil.getTemperatureState(s);
         } catch (NumberFormatException e) {
             logger.warn("An exception occurred while converting '{}' into a State", s);
             return UnDefType.UNDEF;
index 20d2fdb0ae09ceca553a926d798d4b9b27b04ede..13799659e9ad3c247001add8e51916ef62b04397 100644 (file)
@@ -13,9 +13,8 @@
 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.PROTOCOL_PROPERTY_NAME;
+import static org.openhab.binding.miele.internal.MieleBindingConstants.MIELE_DEVICE_CLASS_OVEN;
 
-import org.openhab.binding.miele.internal.FullyQualifiedApplianceIdentifier;
 import org.openhab.core.library.types.OnOffType;
 import org.openhab.core.thing.ChannelUID;
 import org.openhab.core.thing.Thing;
@@ -40,7 +39,7 @@ public class OvenHandler extends MieleApplianceHandler<OvenChannelSelector> {
     private final Logger logger = LoggerFactory.getLogger(OvenHandler.class);
 
     public OvenHandler(Thing thing) {
-        super(thing, OvenChannelSelector.class, "Oven");
+        super(thing, OvenChannelSelector.class, MIELE_DEVICE_CLASS_OVEN);
     }
 
     @Override
@@ -49,8 +48,6 @@ public class OvenHandler extends MieleApplianceHandler<OvenChannelSelector> {
 
         String channelID = channelUID.getId();
         String applianceId = (String) getThing().getConfiguration().getProperties().get(APPLIANCE_ID);
-        String protocol = getThing().getProperties().get(PROTOCOL_PROPERTY_NAME);
-        var applianceIdentifier = new FullyQualifiedApplianceIdentifier(applianceId, protocol);
 
         OvenChannelSelector selector = (OvenChannelSelector) getValueSelectorFromChannelID(channelID);
         JsonElement result = null;
@@ -60,15 +57,15 @@ public class OvenHandler extends MieleApplianceHandler<OvenChannelSelector> {
                 switch (selector) {
                     case SWITCH: {
                         if (command.equals(OnOffType.ON)) {
-                            result = bridgeHandler.invokeOperation(applianceIdentifier, modelID, "switchOn");
+                            result = bridgeHandler.invokeOperation(applianceId, modelID, "switchOn");
                         } else if (command.equals(OnOffType.OFF)) {
-                            result = bridgeHandler.invokeOperation(applianceIdentifier, modelID, "switchOff");
+                            result = bridgeHandler.invokeOperation(applianceId, modelID, "switchOff");
                         }
                         break;
                     }
                     case STOP: {
                         if (command.equals(OnOffType.ON)) {
-                            result = bridgeHandler.invokeOperation(applianceIdentifier, modelID, "stop");
+                            result = bridgeHandler.invokeOperation(applianceId, modelID, "stop");
                         }
                         break;
                     }
@@ -81,7 +78,7 @@ public class OvenHandler extends MieleApplianceHandler<OvenChannelSelector> {
                 }
             }
             // process result
-            if (isResultProcessable(result)) {
+            if (result != null && isResultProcessable(result)) {
                 logger.debug("Result of operation is {}", result.getAsString());
             }
         } catch (IllegalArgumentException e) {
index 8c990860a9dc8e879d3be83b3adc1017fd3ea719..1a375da9e44477068c91e72f19b19867f8294b73 100644 (file)
@@ -47,8 +47,6 @@ public enum TumbleDryerChannelSelector implements ApplianceChannelSelector {
 
     PRODUCT_TYPE("productTypeId", "productType", StringType.class, true),
     DEVICE_TYPE("mieleDeviceType", "deviceType", StringType.class, true),
-    BRAND_ID("brandId", "brandId", StringType.class, true),
-    COMPANY_ID("companyId", "companyId", StringType.class, true),
     STATE_TEXT(STATE_PROPERTY_NAME, STATE_TEXT_CHANNEL_ID, StringType.class, false),
     STATE(null, STATE_CHANNEL_ID, DecimalType.class, false),
     PROGRAM_TEXT(PROGRAM_ID_PROPERTY_NAME, PROGRAM_TEXT_CHANNEL_ID, StringType.class, false) {
@@ -155,7 +153,7 @@ public enum TumbleDryerChannelSelector implements ApplianceChannelSelector {
 
     private final Logger logger = LoggerFactory.getLogger(TumbleDryerChannelSelector.class);
 
-    private final static Map<String, String> programs = Map.ofEntries(entry("10", "Automatic Plus"),
+    private static final Map<String, String> programs = Map.ofEntries(entry("10", "Automatic Plus"),
             entry("23", "Cottons hygiene"), entry("30", "Minimum iron"), entry("31", "Gentle minimum iron"),
             entry("40", "Woollens handcare"), entry("50", "Delicates"), entry("60", "Warm Air"),
             entry("70", "Cool air"), entry("80", "Express"), entry("90", "Cottons"), entry("100", "Gentle smoothing"),
@@ -165,7 +163,7 @@ public enum TumbleDryerChannelSelector implements ApplianceChannelSelector {
             entry("240", "Smoothing"), entry("65000", "Cottons, auto load control"),
             entry("65001", "Minimum iron, auto load control"));
 
-    private final static Map<String, String> phases = Map.ofEntries(entry("1", "Programme running"),
+    private static final Map<String, String> phases = Map.ofEntries(entry("1", "Programme running"),
             entry("2", "Drying"), entry("3", "Drying Machine iron"), entry("4", "Drying Hand iron"),
             entry("5", "Drying Normal"), entry("6", "Drying Normal+"), entry("7", "Cooling down"),
             entry("8", "Drying Hand iron"), entry("10", "Finished"));
index 3ffe5cc12a5133085798112caf497d69597b02cd..7e56d6381fc5e2d96178bbe43e8b9c81f833a6d3 100644 (file)
@@ -13,9 +13,8 @@
 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.PROTOCOL_PROPERTY_NAME;
+import static org.openhab.binding.miele.internal.MieleBindingConstants.MIELE_DEVICE_CLASS_TUMBLE_DRYER;
 
-import org.openhab.binding.miele.internal.FullyQualifiedApplianceIdentifier;
 import org.openhab.core.library.types.OnOffType;
 import org.openhab.core.thing.ChannelUID;
 import org.openhab.core.thing.Thing;
@@ -40,7 +39,7 @@ public class TumbleDryerHandler extends MieleApplianceHandler<TumbleDryerChannel
     private final Logger logger = LoggerFactory.getLogger(TumbleDryerHandler.class);
 
     public TumbleDryerHandler(Thing thing) {
-        super(thing, TumbleDryerChannelSelector.class, "TumbleDryer");
+        super(thing, TumbleDryerChannelSelector.class, MIELE_DEVICE_CLASS_TUMBLE_DRYER);
     }
 
     @Override
@@ -49,8 +48,6 @@ public class TumbleDryerHandler extends MieleApplianceHandler<TumbleDryerChannel
 
         String channelID = channelUID.getId();
         String applianceId = (String) getThing().getConfiguration().getProperties().get(APPLIANCE_ID);
-        String protocol = getThing().getProperties().get(PROTOCOL_PROPERTY_NAME);
-        var applianceIdentifier = new FullyQualifiedApplianceIdentifier(applianceId, protocol);
 
         TumbleDryerChannelSelector selector = (TumbleDryerChannelSelector) getValueSelectorFromChannelID(channelID);
         JsonElement result = null;
@@ -60,9 +57,9 @@ public class TumbleDryerHandler extends MieleApplianceHandler<TumbleDryerChannel
                 switch (selector) {
                     case SWITCH: {
                         if (command.equals(OnOffType.ON)) {
-                            result = bridgeHandler.invokeOperation(applianceIdentifier, modelID, "start");
+                            result = bridgeHandler.invokeOperation(applianceId, modelID, "start");
                         } else if (command.equals(OnOffType.OFF)) {
-                            result = bridgeHandler.invokeOperation(applianceIdentifier, modelID, "stop");
+                            result = bridgeHandler.invokeOperation(applianceId, modelID, "stop");
                         }
                         break;
                     }
@@ -75,7 +72,7 @@ public class TumbleDryerHandler extends MieleApplianceHandler<TumbleDryerChannel
                 }
             }
             // process result
-            if (isResultProcessable(result)) {
+            if (result != null && isResultProcessable(result)) {
                 logger.debug("Result of operation is {}", result.getAsString());
             }
         } catch (IllegalArgumentException e) {
index 714627e69c2e372aa5337c9972060563c15eba29..4fad63fe5dc293c4f3581a37b0b71b57a59fbd46 100644 (file)
@@ -22,8 +22,7 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.TimeZone;
 
-import org.apache.commons.lang3.StringUtils;
-import org.openhab.binding.miele.internal.ExtendedDeviceStateUtil;
+import org.openhab.binding.miele.internal.DeviceUtil;
 import org.openhab.binding.miele.internal.handler.MieleBridgeHandler.DeviceMetaData;
 import org.openhab.core.library.types.DateTimeType;
 import org.openhab.core.library.types.DecimalType;
@@ -50,8 +49,6 @@ public enum WashingMachineChannelSelector implements ApplianceChannelSelector {
 
     PRODUCT_TYPE("productTypeId", "productType", StringType.class, true, false),
     DEVICE_TYPE("mieleDeviceType", "deviceType", StringType.class, true, false),
-    BRAND_ID("brandId", "brandId", StringType.class, true, false),
-    COMPANY_ID("companyId", "companyId", StringType.class, true, false),
     STATE_TEXT(STATE_PROPERTY_NAME, STATE_TEXT_CHANNEL_ID, StringType.class, false, false),
     STATE(null, STATE_CHANNEL_ID, DecimalType.class, false, false),
     PROGRAM_TEXT(PROGRAM_ID_PROPERTY_NAME, PROGRAM_TEXT_CHANNEL_ID, StringType.class, false, false) {
@@ -98,7 +95,7 @@ public enum WashingMachineChannelSelector implements ApplianceChannelSelector {
             SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
             dateFormatter.setTimeZone(TimeZone.getTimeZone("GMT+0"));
             try {
-                date.setTime(Long.valueOf(StringUtils.trim(s)) * 60000);
+                date.setTime(Long.valueOf(s.trim()) * 60000);
             } catch (Exception e) {
                 date.setTime(0);
             }
@@ -174,7 +171,7 @@ public enum WashingMachineChannelSelector implements ApplianceChannelSelector {
 
     private final Logger logger = LoggerFactory.getLogger(WashingMachineChannelSelector.class);
 
-    private final static Map<String, String> programs = Map.ofEntries(entry("1", "Cottons"), entry("3", "Minimum iron"),
+    private static final Map<String, String> programs = Map.ofEntries(entry("1", "Cottons"), entry("3", "Minimum iron"),
             entry("4", "Delicates"), entry("8", "Woollens"), entry("9", "Silks"), entry("17", "Starch"),
             entry("18", "Rinse"), entry("21", "Drain/Spin"), entry("22", "Curtains"), entry("23", "Shirts"),
             entry("24", "Denim"), entry("27", "Proofing"), entry("29", "Sportswear"), entry("31", "Automatic Plus"),
@@ -183,7 +180,7 @@ public enum WashingMachineChannelSelector implements ApplianceChannelSelector {
             entry("95", "Down duvets"), entry("122", "Express 20"), entry("129", "Down filled items"),
             entry("133", "Cottons Eco"), entry("146", "QuickPowerWash"), entry("65532", "Mix"));
 
-    private final static Map<String, String> phases = Map.ofEntries(entry("1", "Pre-wash"), entry("4", "Washing"),
+    private static final Map<String, String> phases = Map.ofEntries(entry("1", "Pre-wash"), entry("4", "Washing"),
             entry("5", "Rinses"), entry("7", "Clean"), entry("9", "Drain"), entry("10", "Spin"),
             entry("11", "Anti-crease"), entry("12", "Finished"));
 
@@ -260,7 +257,7 @@ public enum WashingMachineChannelSelector implements ApplianceChannelSelector {
 
     public State getTemperatureState(String s) {
         try {
-            return ExtendedDeviceStateUtil.getTemperatureState(s);
+            return DeviceUtil.getTemperatureState(s);
         } catch (NumberFormatException e) {
             logger.warn("An exception occurred while converting '{}' into a State", s);
             return UnDefType.UNDEF;
index 350281a45fba0e035c8b77cb5b62ddfeeb1d49f0..4c330cb07bc829217bb3c9509710467db28cd9ef 100644 (file)
 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.PROTOCOL_PROPERTY_NAME;
 import static org.openhab.binding.miele.internal.MieleBindingConstants.WATER_CONSUMPTION_CHANNEL_ID;
 
 import java.math.BigDecimal;
 
-import org.openhab.binding.miele.internal.FullyQualifiedApplianceIdentifier;
 import org.openhab.core.library.types.OnOffType;
 import org.openhab.core.library.types.QuantityType;
 import org.openhab.core.library.unit.Units;
@@ -51,7 +50,7 @@ public class WashingMachineHandler extends MieleApplianceHandler<WashingMachineC
     private final Logger logger = LoggerFactory.getLogger(WashingMachineHandler.class);
 
     public WashingMachineHandler(Thing thing) {
-        super(thing, WashingMachineChannelSelector.class, "WashingMachine");
+        super(thing, WashingMachineChannelSelector.class, MIELE_DEVICE_CLASS_WASHING_MACHINE);
     }
 
     @Override
@@ -60,8 +59,6 @@ public class WashingMachineHandler extends MieleApplianceHandler<WashingMachineC
 
         String channelID = channelUID.getId();
         String applianceId = (String) getThing().getConfiguration().getProperties().get(APPLIANCE_ID);
-        String protocol = getThing().getProperties().get(PROTOCOL_PROPERTY_NAME);
-        var applianceIdentifier = new FullyQualifiedApplianceIdentifier(applianceId, protocol);
 
         WashingMachineChannelSelector selector = (WashingMachineChannelSelector) getValueSelectorFromChannelID(
                 channelID);
@@ -72,9 +69,9 @@ public class WashingMachineHandler extends MieleApplianceHandler<WashingMachineC
                 switch (selector) {
                     case SWITCH: {
                         if (command.equals(OnOffType.ON)) {
-                            result = bridgeHandler.invokeOperation(applianceIdentifier, modelID, "start");
+                            result = bridgeHandler.invokeOperation(applianceId, modelID, "start");
                         } else if (command.equals(OnOffType.OFF)) {
-                            result = bridgeHandler.invokeOperation(applianceIdentifier, modelID, "stop");
+                            result = bridgeHandler.invokeOperation(applianceId, modelID, "stop");
                         }
                         break;
                     }
@@ -87,7 +84,7 @@ public class WashingMachineHandler extends MieleApplianceHandler<WashingMachineC
                 }
             }
             // process result
-            if (isResultProcessable(result)) {
+            if (result != null && isResultProcessable(result)) {
                 logger.debug("Result of operation is {}", result.getAsString());
             }
         } catch (IllegalArgumentException e) {
diff --git a/bundles/org.openhab.binding.miele/src/main/resources/OH-INF/config/config.xml b/bundles/org.openhab.binding.miele/src/main/resources/OH-INF/config/config.xml
new file mode 100644 (file)
index 0000000..8e620c4
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<config-description:config-descriptions
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:config-description="https://openhab.org/schemas/config-description/v1.0.0"
+       xsi:schemaLocation="https://openhab.org/schemas/config-description/v1.0.0
+               https://openhab.org/schemas/config-description-1.0.0.xsd">
+
+       <config-description uri="thing-type:miele:appliance">
+               <parameter name="uid" type="text" required="true">
+                       <label>ID</label>
+                       <description>Unique identifier for specific appliance on the gateway.</description>
+               </parameter>
+       </config-description>
+
+</config-description:config-descriptions>
diff --git a/bundles/org.openhab.binding.miele/src/main/resources/OH-INF/i18n/miele.properties b/bundles/org.openhab.binding.miele/src/main/resources/OH-INF/i18n/miele.properties
new file mode 100644 (file)
index 0000000..94e0949
--- /dev/null
@@ -0,0 +1,107 @@
+# binding
+
+binding.miele.name = Miele Binding
+binding.miele.description = This is the binding for Miele@home appliances
+
+# thing types
+
+thing-type.miele.coffeemachine.label = Coffee Machine
+thing-type.miele.coffeemachine.description = This is a Miele@home compatible coffee machine
+thing-type.miele.dishwasher.label = Dishwasher
+thing-type.miele.dishwasher.description = This is a Miele@home compatible dishwasher
+thing-type.miele.fridge.label = Fridge
+thing-type.miele.fridge.description = This is a Miele@home compatible fridge
+thing-type.miele.fridgefreezer.label = Fridge Freezer
+thing-type.miele.fridgefreezer.description = This is a Miele@home compatible fridgefreezer
+thing-type.miele.hob.label = Hob
+thing-type.miele.hob.description = This is a Miele@home compatible hob
+thing-type.miele.hood.label = Hood
+thing-type.miele.hood.description = This is a Miele@home compatible hood
+thing-type.miele.oven.label = Oven
+thing-type.miele.oven.description = This is a Miele@home compatible oven
+thing-type.miele.tumbledryer.label = Tumbledryer
+thing-type.miele.tumbledryer.description = This is a Miele@home compatible tumbledryer
+thing-type.miele.washingmachine.label = Washing Machine
+thing-type.miele.washingmachine.description = This is a Miele@home compatible washing machine
+thing-type.miele.xgw3000.label = Miele XGW3000
+thing-type.miele.xgw3000.description = The Miele bridge represents the Miele@home XGW3000 gateway.
+
+# thing types config
+
+thing-type.config.miele.appliance.uid.label = ID
+thing-type.config.miele.appliance.uid.description = Unique identifier for specific appliance on the gateway.
+thing-type.config.miele.xgw3000.interface.label = Network Address of the Multicast Interface
+thing-type.config.miele.xgw3000.interface.description = Network address of openHAB host interface where the binding will listen for multicast events coming from the Miele@home gateway.
+thing-type.config.miele.xgw3000.ipAddress.label = Network Address
+thing-type.config.miele.xgw3000.ipAddress.description = Network address of the Miele@home gateway.
+thing-type.config.miele.xgw3000.password.label = Password
+thing-type.config.miele.xgw3000.password.description = Password for the registered Miele@home user.
+thing-type.config.miele.xgw3000.userName.label = Username
+thing-type.config.miele.xgw3000.userName.description = Name of a registered Miele@home user.
+
+# channel types
+
+channel-type.miele.currentTemperature.label = Current Temperature
+channel-type.miele.currentTemperature.description = Current temperature of the appliance
+channel-type.miele.door.label = Door
+channel-type.miele.door.description = Current state of the door of the appliance
+channel-type.miele.duration.label = Duration
+channel-type.miele.duration.description = Duration of the program running on the appliance
+channel-type.miele.duration.state.pattern = %1$tH:%1$tM
+channel-type.miele.elapsed.label = Elapsed Time
+channel-type.miele.elapsed.description = Time elapsed in the program running on the appliance
+channel-type.miele.elapsed.state.pattern = %1$tH:%1$tM
+channel-type.miele.finish.label = Finish Time
+channel-type.miele.finish.description = Time to finish the program running on the appliance
+channel-type.miele.finish.state.pattern = %1$tH:%1$tM
+channel-type.miele.freezerstate.label = Status
+channel-type.miele.freezerstate.description = Current status of the freezer compartment
+channel-type.miele.fridgestate.label = Status
+channel-type.miele.fridgestate.description = Current status of the fridge compartment
+channel-type.miele.heat.label = Remaining Heat
+channel-type.miele.heat.description = Remaining heat level of the heating zone/plate
+channel-type.miele.phase.label = Phase
+channel-type.miele.phase.description = Current phase of the program running on the appliance
+channel-type.miele.plates.label = Plates
+channel-type.miele.plates.description = Number of heating zones/plates on the hob
+channel-type.miele.power.label = Power Step
+channel-type.miele.power.description = Power level of the heating zone/plate
+channel-type.miele.powerConsumption.label = Power Consumption
+channel-type.miele.powerConsumption.description = Power consumption by the currently running program on the appliance
+channel-type.miele.program.label = Program
+channel-type.miele.program.description = Current program or function running on the appliance
+channel-type.miele.rawPhase.label = Raw Phase
+channel-type.miele.rawPhase.description = Current phase of the program running on the appliance as raw number
+channel-type.miele.rawProgram.label = Raw Program
+channel-type.miele.rawProgram.description = Current program or function running on the appliance as raw number
+channel-type.miele.rawState.label = Raw State
+channel-type.miele.rawState.description = Current status of the appliance as raw number
+channel-type.miele.spinningspeed.label = Spinning Speed
+channel-type.miele.spinningspeed.description = Spinning speed in the program running on the appliance
+channel-type.miele.start.label = Start Time
+channel-type.miele.start.description = Programmed start time of the program
+channel-type.miele.start.state.pattern = %1$tH:%1$tM
+channel-type.miele.state.label = State
+channel-type.miele.state.description = Current status of the appliance
+channel-type.miele.step.label = Step
+channel-type.miele.step.description = Current step in the program running on the appliance
+channel-type.miele.stop.label = Stop
+channel-type.miele.stop.description = Stop the appliance
+channel-type.miele.supercool.label = Super Cool
+channel-type.miele.supercool.description = Start or stop Super Cooling
+channel-type.miele.superfreeze.label = Super Freeze
+channel-type.miele.superfreeze.description = Start or stop Super Freezing
+channel-type.miele.switch.label = Switch
+channel-type.miele.switch.description = Switch the appliance on or off
+channel-type.miele.targetTemperature.label = Target Temperature
+channel-type.miele.targetTemperature.description = Target temperature to be reached by the appliance
+channel-type.miele.temperature.label = Temperature
+channel-type.miele.temperature.description = Temperature reported by the appliance
+channel-type.miele.time.label = Remaining Time
+channel-type.miele.time.description = Remaining time of the heating zone/plate
+channel-type.miele.type.label = Program Type
+channel-type.miele.type.description = Type of the program running on the appliance
+channel-type.miele.ventilation.label = Ventilation Power
+channel-type.miele.ventilation.description = Current ventilation power
+channel-type.miele.waterConsumption.label = Water Consumption
+channel-type.miele.waterConsumption.description = Water consumption by the currently running program on the appliance
diff --git a/bundles/org.openhab.binding.miele/src/main/resources/OH-INF/i18n/miele_da.properties b/bundles/org.openhab.binding.miele/src/main/resources/OH-INF/i18n/miele_da.properties
new file mode 100644 (file)
index 0000000..488269b
--- /dev/null
@@ -0,0 +1,40 @@
+# binding
+
+binding.miele.name = Miele Binding
+binding.miele.description = Dette er bindingen til Miele@home-husholdningsapparater
+
+# thing types
+
+thing-type.miele.coffeemachine.label = Kaffemaskine
+thing-type.miele.coffeemachine.description = Dette er en Miele@home-kompatibel kaffemaskine
+thing-type.miele.dishwasher.label = Opvaskemaskine
+thing-type.miele.dishwasher.description = Dette er en Miele@home-kompatibel opvaskemaskine
+thing-type.miele.fridge.label = Køleskab
+thing-type.miele.fridge.description = Dette er et Miele@home-kompatibelt køleskab
+thing-type.miele.fridgefreezer.label = Kølefryseskab
+thing-type.miele.fridgefreezer.description = Dette er et Miele@home-kompatibelt kølefryseskab
+thing-type.miele.hob.label = Kogeplader
+thing-type.miele.hob.description = Dette er Miele@home-kompatible kogeplader
+thing-type.miele.hood.label = Emhætte
+thing-type.miele.hood.description = Dette er en Miele@home-kompatibel emhætte
+thing-type.miele.oven.label = Ovn
+thing-type.miele.oven.description = Dette er en Miele@home-kompatibel ovn
+thing-type.miele.tumbledryer.label = Tørretumbler
+thing-type.miele.tumbledryer.description = Dette er en Miele@home-kompatibel tørretumbler
+thing-type.miele.washingmachine.label = Vaskemaskine
+thing-type.miele.washingmachine.description = Dette er en Miele@home-kompatibel vaskemaskine
+thing-type.miele.xgw3000.label = Miele XGW3000
+thing-type.miele.xgw3000.description = Miele-bridgen repræsenterer Miele@home XGW3000-gateway'en.
+
+# thing types config
+
+thing-type.config.miele.appliance.uid.label = ID
+thing-type.config.miele.appliance.uid.description = Unik identifikator til specifikt husholdningsapparat pÃ¥ gateway'en.
+thing-type.config.miele.xgw3000.interface.label = Netværksadresse til multicast-interfacet
+thing-type.config.miele.xgw3000.interface.description = Netværksadresse til openHAB værts-interfacet hvor bindingen vil lytte pÃ¥ multicast-hændelser fra Miele@home-gateway'en.
+thing-type.config.miele.xgw3000.ipAddress.label = Netværksadresse
+thing-type.config.miele.xgw3000.ipAddress.description = Netværksadresse til Miele@home-gateway'en.
+thing-type.config.miele.xgw3000.password.label = Adgangskode
+thing-type.config.miele.xgw3000.password.description = Adgangskode til registreret Miele@home-bruger.
+thing-type.config.miele.xgw3000.userName.label = Brugernavn
+thing-type.config.miele.xgw3000.userName.description = Navn pÃ¥ en registeret Miele@home-bruger.
index d7ae1d8bcff2a90176bff5c45b95555a7e13502a..92d7a9c3cddb2c2d250e437ee860ed285ee6bce5 100644 (file)
 
                <representation-property>uid</representation-property>
 
-               <config-description>
-                       <parameter name="uid" type="text" required="true">
-                               <label>ID</label>
-                               <description>The identifier identifies one certain appliance on the ZigBee network.</description>
-                       </parameter>
-               </config-description>
+               <config-description-ref uri="thing-type:miele:appliance"/>
        </thing-type>
 
 </thing:thing-descriptions>
index a50081e91ac7300866ba9c843bfd1fc55838ffba..dbcd85123999e680699ce5baed649ecb46f20442 100644 (file)
 
                <representation-property>uid</representation-property>
 
-               <config-description>
-                       <parameter name="uid" type="text" required="true">
-                               <label>ID</label>
-                               <description>The identifier identifies one certain appliance on the ZigBee network.</description>
-                       </parameter>
-               </config-description>
-
+               <config-description-ref uri="thing-type:miele:appliance"/>
        </thing-type>
 
 </thing:thing-descriptions>
index 8e154f1870ffa4feb8555dae88ed0f6123f3f2a8..4685f0cfad65093fab0a2603e1632a5f6619bbee 100644 (file)
 
                <representation-property>uid</representation-property>
 
-               <config-description>
-                       <parameter name="uid" type="text" required="true">
-                               <label>ID</label>
-                               <description>The identifier identifies one certain appliance on the ZigBee network.</description>
-                       </parameter>
-               </config-description>
-
+               <config-description-ref uri="thing-type:miele:appliance"/>
        </thing-type>
 
 </thing:thing-descriptions>
index c257767d84063f80a5407c89e9840df0b27a11e6..23fe18099daeacb37741fff98bb3f8ed395e5198 100644 (file)
 
                <representation-property>uid</representation-property>
 
-               <config-description>
-                       <parameter name="uid" type="text" required="true">
-                               <label>ID</label>
-                               <description>The identifier identifies one certain appliance on the ZigBee network.</description>
-                       </parameter>
-               </config-description>
-
+               <config-description-ref uri="thing-type:miele:appliance"/>
        </thing-type>
 
 </thing:thing-descriptions>
index a3897500329d8ff746aa0c0f09d7525da5300425..ce387651976b4a0fb8bd0d392aab5e248e1a5811 100644 (file)
 
                <representation-property>uid</representation-property>
 
-               <config-description>
-                       <parameter name="uid" type="text" required="true">
-                               <label>ID</label>
-                               <description>The identifier identifies one certain appliance on the ZigBee network.</description>
-                       </parameter>
-               </config-description>
-
+               <config-description-ref uri="thing-type:miele:appliance"/>
        </thing-type>
 
 </thing:thing-descriptions>
index a396b962de4e3a70b4f73e7d36b723f4977a6041..77888cc0c0c88bd7ca234498bbc390e5afb6428b 100644 (file)
 
                <representation-property>uid</representation-property>
 
-               <config-description>
-                       <parameter name="uid" type="text" required="true">
-                               <label>ID</label>
-                               <description>The identifier identifies the appliance on the ZigBee network.</description>
-                       </parameter>
-               </config-description>
+               <config-description-ref uri="thing-type:miele:appliance"/>
        </thing-type>
 
 </thing:thing-descriptions>
index 58fa91d19679e441ff7d47deda36d08e52f3bd4c..98dd1b5b7e0d5532ae948f14be33b073c1c0f2bb 100644 (file)
 
                <representation-property>uid</representation-property>
 
-               <config-description>
-                       <parameter name="uid" type="text" required="true">
-                               <label>ID</label>
-                               <description>The identifier identifies one certain appliance on the ZigBee network.</description>
-                       </parameter>
-               </config-description>
-
+               <config-description-ref uri="thing-type:miele:appliance"/>
        </thing-type>
 
 </thing:thing-descriptions>
index ea5716fb9a26b73446d09f4eeab0aea22c7a0127..8655a1f3674d695f3abab33384a8dd20759df495 100644 (file)
 
                <representation-property>uid</representation-property>
 
-               <config-description>
-                       <parameter name="uid" type="text" required="true">
-                               <label>ID</label>
-                               <description>The identifier identifies one certain appliance on the ZigBee network.</description>
-                       </parameter>
-               </config-description>
-
+               <config-description-ref uri="thing-type:miele:appliance"/>
        </thing-type>
 
 
index 39a2a95b5ac622c97366a466c0a514edf1f27b6d..d704a54bffc05c32ca74ab449cd6cad4da04aebe 100644 (file)
 
                <representation-property>uid</representation-property>
 
-               <config-description>
-                       <parameter name="uid" type="text" required="true">
-                               <label>ID</label>
-                               <description>The identifier identifies one certain appliance on the ZigBee network.</description>
-                       </parameter>
-               </config-description>
+               <config-description-ref uri="thing-type:miele:appliance"/>
        </thing-type>
 
 </thing:thing-descriptions>
index bdabbde84332cab0b6fe677201124f2a2b231edf..58d9ca23cbac49911f9db804f20ca96a8c9fea3e 100644 (file)
@@ -7,7 +7,7 @@
        <!-- Miele Bridge -->
        <bridge-type id="xgw3000">
                <label>Miele XGW3000</label>
-               <description>The miele bridge represents the Miele@home XGW3000 gateway.</description>
+               <description>The Miele bridge represents the Miele@home XGW3000 gateway.</description>
 
                <properties>
                        <property name="vendor">Miele</property>
@@ -25,7 +25,7 @@
                                <context>network-address</context>
                                <label>Network Address of the Multicast Interface</label>
                                <description>Network address of openHAB host interface where the binding will listen for multicast events coming
-                                       from the Miele@home gateway</description>
+                                       from the Miele@home gateway.</description>
                        </parameter>
                        <parameter name="userName" type="text" required="false">
                                <label>Username</label>
@@ -36,7 +36,7 @@
                        <parameter name="password" type="text" required="false">
                                <context>password</context>
                                <label>Password</label>
-                               <description>Password for the registered Miele@home</description>
+                               <description>Password for the registered Miele@home user.</description>
                        </parameter>
                </config-description>
        </bridge-type>
diff --git a/bundles/org.openhab.binding.miele/src/test/java/org/openhab/binding/miele/internal/DeviceUtilTest.java b/bundles/org.openhab.binding.miele/src/test/java/org/openhab/binding/miele/internal/DeviceUtilTest.java
new file mode 100644 (file)
index 0000000..d159dd5
--- /dev/null
@@ -0,0 +1,70 @@
+/**
+ * Copyright (c) 2010-2021 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.miele.internal;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import org.junit.jupiter.api.Test;
+import org.openhab.core.library.types.QuantityType;
+import org.openhab.core.library.unit.SIUnits;
+import org.openhab.core.test.java.JavaTest;
+import org.openhab.core.types.UnDefType;
+
+/**
+ * This class provides test cases for {@link
+ * org.openhab.binding.miele.internal.DeviceUtil}
+ *
+ * @author Jacob Laursen - Initial contribution
+ */
+
+public class DeviceUtilTest extends JavaTest {
+
+    @Test
+    public void bytesToHexWhenTopBitIsUsedReturnsCorrectString() {
+        String actual = DeviceUtil.bytesToHex(new byte[] { (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef });
+        assertEquals("DEADBEEF", actual);
+    }
+
+    /**
+     * This test guards that the UTF-16 returned by the RPC-JSON API will be
+     * considered as a sequence of 8-bit characters and converted into bytes
+     * accordingly. Default behaviour of String.getBytes() assumes UTF-8
+     * and adds a 0xc2 byte before any character out of ASCII range.
+     */
+    @Test
+    public void stringToBytesWhenTopBitIsUsedReturnsSingleByte() {
+        byte[] expected = new byte[] { (byte) 0x00, (byte) 0x80, (byte) 0x00 };
+        byte[] actual = DeviceUtil.stringToBytes("\u0000\u0080\u0000");
+        assertArrayEquals(expected, actual);
+    }
+
+    @Test
+    public void getTemperatureStateWellFormedValueReturnsQuantityType() throws NumberFormatException {
+        assertEquals(new QuantityType<>(42, SIUnits.CELSIUS), DeviceUtil.getTemperatureState("42"));
+    }
+
+    @Test
+    public void getTemperatureStateMagicValueReturnsUndefined() throws NumberFormatException {
+        assertEquals(UnDefType.UNDEF, DeviceUtil.getTemperatureState("32768"));
+    }
+
+    @Test
+    public void getTemperatureStateNonNumericValueThrowsNumberFormatException() {
+        assertThrows(NumberFormatException.class, () -> DeviceUtil.getTemperatureState("A"));
+    }
+
+    @Test
+    public void getTemperatureStateNullValueThrowsNumberFormatException() {
+        assertThrows(NumberFormatException.class, () -> DeviceUtil.getTemperatureState(null));
+    }
+}
diff --git a/bundles/org.openhab.binding.miele/src/test/java/org/openhab/binding/miele/internal/ExtendedDeviceStateUtilTest.java b/bundles/org.openhab.binding.miele/src/test/java/org/openhab/binding/miele/internal/ExtendedDeviceStateUtilTest.java
deleted file mode 100644 (file)
index 88c2518..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/**
- * Copyright (c) 2010-2021 Contributors to the openHAB project
- *
- * See the NOTICE file(s) distributed with this work for additional
- * information.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License 2.0 which is available at
- * http://www.eclipse.org/legal/epl-2.0
- *
- * SPDX-License-Identifier: EPL-2.0
- */
-package org.openhab.binding.miele.internal;
-
-import static org.junit.jupiter.api.Assertions.*;
-
-import org.junit.jupiter.api.Test;
-import org.openhab.core.library.types.QuantityType;
-import org.openhab.core.library.unit.SIUnits;
-import org.openhab.core.test.java.JavaTest;
-import org.openhab.core.types.UnDefType;
-
-/**
- * This class provides test cases for {@link
- * org.openhab.binding.miele.internal.ExtendedDeviceStateUtil}
- *
- * @author Jacob Laursen - Added power/water consumption channels
- */
-
-public class ExtendedDeviceStateUtilTest extends JavaTest {
-
-    @Test
-    public void bytesToHexWhenTopBitIsUsedReturnsCorrectString() {
-        String actual = ExtendedDeviceStateUtil
-                .bytesToHex(new byte[] { (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef });
-        assertEquals("DEADBEEF", actual);
-    }
-
-    /**
-     * This test guards that the UTF-16 returned by the RPC-JSON API will be
-     * considered as a sequence of 8-bit characters and converted into bytes
-     * accordingly. Default behaviour of String.getBytes() assumes UTF-8
-     * and adds a 0xc2 byte before any character out of ASCII range.
-     */
-    @Test
-    public void stringToBytesWhenTopBitIsUsedReturnsSingleByte() {
-        byte[] expected = new byte[] { (byte) 0x00, (byte) 0x80, (byte) 0x00 };
-        byte[] actual = ExtendedDeviceStateUtil.stringToBytes("\u0000\u0080\u0000");
-        assertArrayEquals(expected, actual);
-    }
-
-    @Test
-    public void getTemperatureStateWellFormedValueReturnsQuantityType() throws NumberFormatException {
-        assertEquals(new QuantityType<>(42, SIUnits.CELSIUS), ExtendedDeviceStateUtil.getTemperatureState("42"));
-    }
-
-    @Test
-    public void getTemperatureStateMagicValueReturnsUndefined() throws NumberFormatException {
-        assertEquals(UnDefType.UNDEF, ExtendedDeviceStateUtil.getTemperatureState("32768"));
-    }
-
-    @Test
-    public void getTemperatureStateNonNumericValueThrowsNumberFormatException() {
-        assertThrows(NumberFormatException.class, () -> ExtendedDeviceStateUtil.getTemperatureState("A"));
-    }
-
-    @Test
-    public void getTemperatureStateNullValueThrowsNumberFormatException() {
-        assertThrows(NumberFormatException.class, () -> ExtendedDeviceStateUtil.getTemperatureState(null));
-    }
-}
index f352b6cff5f4351c184b6c21965de37c20140c43..5b8923da3a320bd2487215b9669e9f9ec8609c6e 100644 (file)
@@ -21,7 +21,7 @@ import org.openhab.core.test.java.JavaTest;
  * This class provides test cases for {@link
  * org.openhab.binding.miele.internal.FullyQualifiedApplianceIdentifier}
  *
- * @author Jacob Laursen - Fixed multicast and protocol support (ZigBee/LAN)
+ * @author Jacob Laursen - Initial contribution
  */
 public class FullyQualifiedApplianceIdentifierTest extends JavaTest {