]> git.basschouten.com Git - openhab-addons.git/commitdiff
[knx] Improve reading of device properties (#14050)
authorHolger Friedrich <holgerfriedrich@users.noreply.github.com>
Tue, 7 Mar 2023 18:31:39 +0000 (19:31 +0100)
committerGitHub <noreply@github.com>
Tue, 7 Mar 2023 18:31:39 +0000 (19:31 +0100)
* [knx] Improve reading of device properties
* [knx] DD2 logging only in debug mode

Signed-off-by: Holger Friedrich <mail@holger-friedrich.de>
bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/KNXBindingConstants.java
bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/client/DeviceInfoClient.java
bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/client/DeviceInfoClientImpl.java
bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/client/DeviceInspector.java
bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/handler/DeviceConstants.java
bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/handler/Firmware.java [deleted file]
bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/handler/Manufacturer.java

index 948aae7c83bfd652622029c49b40091972be100e..b2557e545f731aaa7797151e44534fdaad9d6183 100644 (file)
@@ -38,13 +38,16 @@ public class KNXBindingConstants {
     public static final ThingTypeUID THING_TYPE_DEVICE = new ThingTypeUID(BINDING_ID, "device");
 
     // Property IDs
-    public static final String FIRMWARE_TYPE = "firmwaretype";
-    public static final String FIRMWARE_VERSION = "firmwareversion";
-    public static final String FIRMWARE_SUBVERSION = "firmwaresubversion";
-    public static final String MANUFACTURER_NAME = "manfacturername";
-    public static final String MANUFACTURER_SERIAL_NO = "manfacturerserialnumber";
-    public static final String MANUFACTURER_HARDWARE_TYPE = "manfacturerhardwaretype";
-    public static final String MANUFACTURER_FIRMWARE_REVISION = "manfacturerfirmwarerevision";
+    public static final String DEVICE_MASK_VERSION = "deviceMaskVersion";
+    public static final String DEVICE_PROFILE = "deviceProfile";
+    public static final String DEVICE_MEDIUM_TYPE = "deviceMediumType";
+    public static final String FRIENDLY_NAME = "deviceName";
+    public static final String MANUFACTURER_NAME = "manufacturerName";
+    public static final String MANUFACTURER_SERIAL_NO = "manufacturerSerialNumber";
+    public static final String MANUFACTURER_HARDWARE_TYPE = "manufacturerHardwareType";
+    public static final String MANUFACTURER_FIRMWARE_REVISION = "manufacturerFirmwareRevision";
+    public static final String MANUFACTURER_ORDER_INFO = "manufacturerOrderInfo";
+    public static final String MAX_APDU_LENGTH = "maxApduLength";
 
     // Thing Configuration parameters
     public static final String IP_ADDRESS = "ipAddress";
index c46f26db90f3176ed898f2ea77aef4544462cf75..32677057dc0246e3357d578c4a2d757f4c670fae 100644 (file)
@@ -26,14 +26,15 @@ import tuwien.auto.calimero.IndividualAddress;
 @NonNullByDefault
 public interface DeviceInfoClient {
 
-    byte @Nullable [] readDeviceDescription(IndividualAddress address, int descType, boolean authenticate,
-            long timeout);
+    byte @Nullable [] readDeviceDescription(IndividualAddress address, int descType, boolean authenticate, long timeout)
+            throws InterruptedException;
 
     byte @Nullable [] readDeviceMemory(IndividualAddress address, int startAddress, int bytes, boolean authenticate,
-            long timeout);
+            long timeout) throws InterruptedException;
 
     byte @Nullable [] readDeviceProperties(IndividualAddress address, final int interfaceObjectIndex,
-            final int propertyId, final int start, final int elements, boolean authenticate, long timeout);
+            final int propertyId, final int start, final int elements, boolean authenticate, long timeout)
+            throws InterruptedException;
 
     public boolean isConnected();
 }
index 5c6724824501a2f2d0165850b4e7d6d0ac13bf5b..b497956142cbeac1111741b172dfa2699daacd55 100644 (file)
@@ -49,7 +49,7 @@ public class DeviceInfoClientImpl implements DeviceInfoClient {
     }
 
     private byte @Nullable [] readFromManagementClient(String task, long timeout, IndividualAddress address,
-            ReadFunction<Destination, byte[]> function) {
+            ReadFunction<Destination, byte[]> function) throws InterruptedException {
         final long start = System.nanoTime();
         while ((System.nanoTime() - start) < TimeUnit.MILLISECONDS.toNanos(timeout)) {
             Destination destination = null;
@@ -68,7 +68,7 @@ public class DeviceInfoClientImpl implements DeviceInfoClient {
                 }
             } catch (InterruptedException e) {
                 logger.trace("Interrupted to {}", task);
-                return null;
+                throw e;
             } finally {
                 if (destination != null) {
                     destination.destroy();
@@ -87,7 +87,7 @@ public class DeviceInfoClientImpl implements DeviceInfoClient {
 
     @Override
     public synchronized byte @Nullable [] readDeviceDescription(IndividualAddress address, int descType,
-            boolean authenticate, long timeout) {
+            boolean authenticate, long timeout) throws InterruptedException {
         String task = "read the device description";
         return readFromManagementClient(task, timeout, address, destination -> {
             authorize(authenticate, destination);
@@ -97,7 +97,7 @@ public class DeviceInfoClientImpl implements DeviceInfoClient {
 
     @Override
     public synchronized byte @Nullable [] readDeviceMemory(IndividualAddress address, int startAddress, int bytes,
-            boolean authenticate, long timeout) {
+            boolean authenticate, long timeout) throws InterruptedException {
         String task = MessageFormat.format("read {0} bytes at memory location {1}", bytes, startAddress);
         return readFromManagementClient(task, timeout, address, destination -> {
             authorize(authenticate, destination);
@@ -108,7 +108,7 @@ public class DeviceInfoClientImpl implements DeviceInfoClient {
     @Override
     public synchronized byte @Nullable [] readDeviceProperties(IndividualAddress address,
             final int interfaceObjectIndex, final int propertyId, final int start, final int elements,
-            boolean authenticate, long timeout) {
+            boolean authenticate, long timeout) throws InterruptedException {
         String task = MessageFormat.format("read device property {0} at index {1}", propertyId, interfaceObjectIndex);
         return readFromManagementClient(task, timeout, address, destination -> {
             authorize(authenticate, destination);
index 488de983244059117520e4e2487cc119b4b8dc49..4e0f05da6ba0e8d3fa7d9d2d1cad8af0ec12d675 100644 (file)
@@ -22,7 +22,6 @@ import java.util.Set;
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.jdt.annotation.Nullable;
-import org.openhab.binding.knx.internal.handler.Firmware;
 import org.openhab.binding.knx.internal.handler.Manufacturer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -30,14 +29,17 @@ import org.slf4j.LoggerFactory;
 import tuwien.auto.calimero.DataUnitBuilder;
 import tuwien.auto.calimero.DeviceDescriptor;
 import tuwien.auto.calimero.DeviceDescriptor.DD0;
+import tuwien.auto.calimero.DeviceDescriptor.DD2;
 import tuwien.auto.calimero.GroupAddress;
 import tuwien.auto.calimero.IndividualAddress;
+import tuwien.auto.calimero.KNXIllegalArgumentException;
 import tuwien.auto.calimero.mgmt.PropertyAccess.PID;
 
 /**
  * Client dedicated to read device specific information using the {@link DeviceInfoClient}.
  *
  * @author Simon Kaufmann - initial contribution and API.
+ * @author Holger Friedrich - support additional device properties
  *
  */
 @NonNullByDefault
@@ -78,6 +80,15 @@ public class DeviceInspector {
         return client;
     }
 
+    /**
+     * {@link readDeviceInfo} tries to read information from the KNX device.
+     * This function catches {@link java.lang.InterruptedException}. It can safely be cancelled.
+     *
+     * The number of properties returned by this function depends on the data provided
+     * by the KNX device.
+     *
+     * @return List of device properties
+     */
     @Nullable
     public Result readDeviceInfo() {
         if (!getClient().isConnected()) {
@@ -86,48 +97,184 @@ public class DeviceInspector {
 
         logger.debug("Fetching device information for address {}", address);
         Map<String, String> properties = new HashMap<>();
-        properties.putAll(readDeviceDescription(address));
-        properties.putAll(readDeviceProperties(address));
+        try {
+            properties.putAll(readDeviceDescription(address));
+            properties.putAll(readDeviceProperties(address));
+        } catch (InterruptedException e) {
+            final String msg = e.getMessage();
+            logger.debug("Interrupted while fetching the device description for a device '{}' {}", address,
+                    msg != null ? ": " + msg : "");
+        }
         return new Result(properties, Collections.emptySet());
     }
 
-    private Map<String, String> readDeviceProperties(IndividualAddress address) {
+    /**
+     * @implNote {@link readDeviceProperties(address)} tries to read several properties from the KNX device.
+     *           Errors reading single properties are ignored, the respective item is skipped and readout continues
+     *           with next property. {@link java.lang.InterruptedException} is thrown to allow for stopping the readout
+     *           task immediately on connection loss or thing deconstruction.
+     *
+     * @param address Individual address of KNX device
+     * @return List of device properties
+     * @throws InterruptedException
+     */
+    private Map<String, String> readDeviceProperties(IndividualAddress address) throws InterruptedException {
         Map<String, String> ret = new HashMap<>();
-        try {
+        Thread.sleep(OPERATION_INTERVAL);
+        // check if there is a Device Object in the KNX device
+        byte[] elements = getClient().readDeviceProperties(address, DEVICE_OBJECT, PID.OBJECT_TYPE, 0, 1, false,
+                OPERATION_TIMEOUT);
+        if ((elements == null ? 0 : toUnsigned(elements)) == 1) {
             Thread.sleep(OPERATION_INTERVAL);
-            // check if there is a Device Object in the KNX device
-            byte[] elements = getClient().readDeviceProperties(address, DEVICE_OBJECT, PID.OBJECT_TYPE, 0, 1, false,
-                    OPERATION_TIMEOUT);
-            if ((elements == null ? 0 : toUnsigned(elements)) == 1) {
-                Thread.sleep(OPERATION_INTERVAL);
-                String manufacturerID = Manufacturer.getName(toUnsigned(getClient().readDeviceProperties(address,
-                        DEVICE_OBJECT, PID.MANUFACTURER_ID, 1, 1, false, OPERATION_TIMEOUT)));
-                Thread.sleep(OPERATION_INTERVAL);
-                String serialNo = toHex(getClient().readDeviceProperties(address, DEVICE_OBJECT, PID.SERIAL_NUMBER, 1,
-                        1, false, OPERATION_TIMEOUT), "");
-                Thread.sleep(OPERATION_INTERVAL);
-                String hardwareType = toHex(getClient().readDeviceProperties(address, DEVICE_OBJECT, HARDWARE_TYPE, 1,
-                        1, false, OPERATION_TIMEOUT), " ");
+            String manufacturerID = Manufacturer.getName(toUnsigned(getClient().readDeviceProperties(address,
+                    DEVICE_OBJECT, PID.MANUFACTURER_ID, 1, 1, false, OPERATION_TIMEOUT)));
+
+            Thread.sleep(OPERATION_INTERVAL);
+            String serialNo = toHex(getClient().readDeviceProperties(address, DEVICE_OBJECT, PID.SERIAL_NUMBER, 1, 1,
+                    false, OPERATION_TIMEOUT), "");
+
+            Thread.sleep(OPERATION_INTERVAL);
+            String hardwareType = toHex(getClient().readDeviceProperties(address, DEVICE_OBJECT, HARDWARE_TYPE, 1, 1,
+                    false, OPERATION_TIMEOUT), " ");
+
+            // PID_FIRMWARE_REVISION, optional, fallback PID_VERSION according to spec
+            Thread.sleep(OPERATION_INTERVAL);
+            String firmwareRevision = null;
+            try {
+                byte[] result = getClient().readDeviceProperties(address, DEVICE_OBJECT, PID.FIRMWARE_REVISION, 1, 1,
+                        false, OPERATION_TIMEOUT);
+                if (result != null) {
+                    firmwareRevision = Integer.toString(toUnsigned(result));
+                } else {
+                    // try fallback to PID_VERSION
+                    Thread.sleep(OPERATION_INTERVAL);
+                    result = getClient().readDeviceProperties(address, DEVICE_OBJECT, PID.VERSION, 1, 1, false,
+                            OPERATION_TIMEOUT);
+                    if (result != null) {
+                        // data format is DPT217.001
+                        int i = toUnsigned(result);
+                        firmwareRevision = Integer.toString((i & 0xF800) >> 11) + "."
+                                + Integer.toString((i & 0x07C0) >> 6) + "." + Integer.toString((i & 0x003F));
+                    }
+                }
+            } catch (InterruptedException e) {
+                throw e;
+            } catch (Exception ignore) {
+                // allowed to fail, optional
+            }
+
+            // MAX_APDU_LENGTH, for *routing*, optional, fallback to MAX_APDU_LENGTH of device
+            Thread.sleep(OPERATION_INTERVAL);
+            String maxApdu = "";
+            try {
+                byte[] result = getClient().readDeviceProperties(address, DEVICE_OBJECT, PID.MAX_APDULENGTH, 1, 1,
+                        false, OPERATION_TIMEOUT);
+                if (result != null) {
+                    maxApdu = Integer.toString(toUnsigned(result));
+                }
+            } catch (InterruptedException e) {
+                throw e;
+            } catch (Exception ignore) {
+                // allowed to fail, optional
+            }
+            if (!maxApdu.isEmpty()) {
+                logger.trace("Max APDU of device {} is {} bytes (routing)", address, maxApdu);
+            } else {
+                // fallback: MAX_APDU_LENGTH; if availble set the default is 14 according to spec
                 Thread.sleep(OPERATION_INTERVAL);
-                String firmwareRevision = Integer.toString(toUnsigned(getClient().readDeviceProperties(address,
-                        DEVICE_OBJECT, PID.FIRMWARE_REVISION, 1, 1, false, OPERATION_TIMEOUT)));
+                try {
+                    byte[] result = getClient().readDeviceProperties(address, ADDRESS_TABLE_OBJECT,
+                            MAX_ROUTED_APDU_LENGTH, 1, 1, false, OPERATION_TIMEOUT);
+                    if (result != null) {
+                        maxApdu = Integer.toString(toUnsigned(result));
+                    }
+                } catch (InterruptedException e) {
+                    throw e;
+                } catch (Exception ignore) {
+                    // allowed to fail, optional
+                }
+                if (!maxApdu.isEmpty()) {
+                    logger.trace("Max APDU of device {} is {} bytes", address, maxApdu);
+                } else {
+                    logger.trace("Max APDU of device {} not set, fallback to 14 bytes", address);
+                    maxApdu = "14"; // see spec
+                }
+            }
 
-                ret.put(MANUFACTURER_NAME, manufacturerID);
-                if (serialNo != null) {
-                    ret.put(MANUFACTURER_SERIAL_NO, serialNo);
+            Thread.sleep(OPERATION_INTERVAL);
+            byte[] orderInfo = getClient().readDeviceProperties(address, DEVICE_OBJECT, PID.ORDER_INFO, 1, 1, false,
+                    OPERATION_TIMEOUT);
+            if (orderInfo != null) {
+                final String hexString = toHex(orderInfo, "");
+                if (!"ffffffffffffffffffff".equals(hexString) && !"00000000000000000000".equals(hexString)) {
+                    String result = new String(orderInfo);
+                    result = result.trim();
+                    if (result.isEmpty()) {
+                        result = "0x" + hexString;
+                    } else {
+                        final String printable = result.replaceAll("[^\\x20-\\x7E]", ".");
+                        if (!printable.equals(result)) {
+                            result = printable + " (0x" + hexString + ")";
+                        }
+                    }
+                    logger.trace("Order code of device {} is \"{}\"", address, result);
+                    ret.put(MANUFACTURER_ORDER_INFO, result);
                 }
-                if (hardwareType != null) {
-                    ret.put(MANUFACTURER_HARDWARE_TYPE, hardwareType);
+            }
+
+            // read FRIENDLY_NAME, optional
+            Thread.sleep(OPERATION_INTERVAL);
+            try {
+                byte[] count = getClient().readDeviceProperties(address, ROUTER_OBJECT, PID.FRIENDLY_NAME, 0, 1, false,
+                        OPERATION_TIMEOUT);
+                if ((count != null) && (toUnsigned(count) == 30)) {
+                    StringBuffer buf = new StringBuffer(30);
+                    for (int i = 1; i <= 30; i++) {
+                        Thread.sleep(OPERATION_INTERVAL);
+                        // for some reason, reading more than one character per message fails
+                        // reading only one character is inefficient, but works
+                        byte[] data = getClient().readDeviceProperties(address, ROUTER_OBJECT, PID.FRIENDLY_NAME, i, 1,
+                                false, OPERATION_TIMEOUT);
+                        if (toUnsigned(data) != 0) {
+                            if (data != null) {
+                                buf.append(new String(data));
+                            }
+                        } else {
+                            break;
+                        }
+                    }
+                    final String result = buf.toString();
+                    if (result.matches("^[\\x20-\\x7E]+$")) {
+                        logger.debug("Identified device {} as \"{}\"", address, result);
+                        ret.put(FRIENDLY_NAME, result);
+                    } else {
+                        // this is due to devices which have a buggy implememtation (and show a broken string also
+                        // in ETS tool)
+                        logger.debug("Ignoring FRIENDLY_NAME of device {} as it contains non-printable characters",
+                                address);
+                    }
                 }
+            } catch (InterruptedException e) {
+                throw e;
+            } catch (Exception e) {
+                // allowed to fail, optional
+            }
+
+            ret.put(MANUFACTURER_NAME, manufacturerID);
+            if (serialNo != null) {
+                ret.put(MANUFACTURER_SERIAL_NO, serialNo);
+            }
+            if (hardwareType != null) {
+                ret.put(MANUFACTURER_HARDWARE_TYPE, hardwareType);
+            }
+            if (firmwareRevision != null) {
                 ret.put(MANUFACTURER_FIRMWARE_REVISION, firmwareRevision);
-                logger.debug("Identified device {} as a {}, type {}, revision {}, serial number {}", address,
-                        manufacturerID, hardwareType, firmwareRevision, serialNo);
-            } else {
-                logger.debug("The KNX device with address {} does not expose a Device Object", address);
             }
-        } catch (InterruptedException e) {
-            logger.debug("Interrupted while fetching the device description for a device '{}' : {}", address,
-                    e.getMessage());
+            ret.put(MAX_APDU_LENGTH, maxApdu);
+            logger.debug("Identified device {} as {}, type {}, revision {}, serial number {}, max APDU {}", address,
+                    manufacturerID, hardwareType, firmwareRevision, serialNo, maxApdu);
+        } else {
+            logger.debug("The KNX device with address {} does not expose a Device Object", address);
         }
         return ret;
     }
@@ -136,20 +283,45 @@ public class DeviceInspector {
         return input == null ? null : DataUnitBuilder.toHex(input, separator);
     }
 
-    private Map<String, String> readDeviceDescription(IndividualAddress address) {
+    /**
+     * @implNote {@link readDeviceDescription(address)} tries to read device description from the KNX device.
+     *           According to KNX specification, eihter device descriptor DD0 or DD2 must be implemented.
+     *           Currently only data from DD0 is returned; DD2 is just logged in debug mode.
+     *
+     * @param address Individual address of KNX device
+     * @return List of device properties
+     * @throws InterruptedException
+     */
+    private Map<String, String> readDeviceDescription(IndividualAddress address) throws InterruptedException {
         Map<String, String> ret = new HashMap<>();
         byte[] data = getClient().readDeviceDescription(address, 0, false, OPERATION_TIMEOUT);
         if (data != null) {
-            final DD0 dd = DeviceDescriptor.DD0.from(data);
-
-            ret.put(FIRMWARE_TYPE, Firmware.getName(dd.firmwareType()));
-            ret.put(FIRMWARE_VERSION, Firmware.getName(dd.firmwareVersion()));
-            ret.put(FIRMWARE_SUBVERSION, Firmware.getName(dd.firmwareSubcode()));
-            logger.debug("The device with address {} is of type {}, version {}, subversion {}", address,
-                    Firmware.getName(dd.firmwareType()), Firmware.getName(dd.firmwareVersion()),
-                    Firmware.getName(dd.firmwareSubcode()));
+            try {
+                final DD0 dd = DeviceDescriptor.DD0.from(data);
+
+                ret.put(DEVICE_MASK_VERSION, String.format("%04X", dd.maskVersion()));
+                ret.put(DEVICE_PROFILE, dd.deviceProfile());
+                ret.put(DEVICE_MEDIUM_TYPE, getMediumType(dd.mediumType()));
+                logger.debug("The device with address {} has mask {} ({}, medium {})", address,
+                        ret.get(DEVICE_MASK_VERSION), ret.get(DEVICE_PROFILE), ret.get(DEVICE_MEDIUM_TYPE));
+            } catch (KNXIllegalArgumentException e) {
+                logger.warn("Can not parse Device Descriptor 0 of device with address {}: {}", address, e.getMessage());
+            }
         } else {
-            logger.debug("The KNX device with address {} does not expose a Device Descriptor", address);
+            logger.debug("The device with address {} does not expose a Device Descriptor type 0", address);
+        }
+        if (logger.isDebugEnabled()) {
+            Thread.sleep(OPERATION_INTERVAL);
+            data = getClient().readDeviceDescription(address, 2, false, OPERATION_TIMEOUT);
+            if (data != null) {
+                try {
+                    final DD2 dd = DeviceDescriptor.DD2.from(data);
+                    logger.debug("The device with address {} is has DD2 {}", address, dd.toString());
+                } catch (KNXIllegalArgumentException e) {
+                    logger.warn("Can not parse device descriptor 2 of device with address {}: {}", address,
+                            e.getMessage());
+                }
+            }
         }
         return ret;
     }
@@ -169,4 +341,23 @@ public class DeviceInspector {
         value = value << 16 | data[2] & 0xff << 8 | data[3] & 0xff;
         return value;
     }
+
+    private static String getMediumType(int type) {
+        switch (type) {
+            case 0:
+                return "TP";
+            case 1:
+                return "PL";
+            case 2:
+                return "RF";
+            case 3:
+                return "TP0 (deprecated)";
+            case 4:
+                return "PL123 (deprecated)";
+            case 5:
+                return "IP";
+            default:
+                return "unknown (" + type + ")";
+        }
+    }
 }
index 391adb4919d3a3967482e8420bc1ea5678a50d5b..82623aa34024d24050cebec45d54b92d5b374930 100644 (file)
@@ -41,9 +41,13 @@ public class DeviceConstants {
     public static final int ASSOCIATION_TABLE_OBJECT = 2; // Associationtable Object
     public static final int APPLICATION_PROGRAM_TABLE = 3; // Application Program Object
     public static final int INTERFACE_PROGRAM_OBJECT = 4; // Interface Program Object
+    public static final int ROUTER_OBJECT = 6; // Router Object
     public static final int GROUPOBJECT_OBJECT = 9; // Group Object Object
     public static final int KNXNET_IP_OBJECT = 11; // KNXnet/IP Parameter Object
 
     // Property IDs for device information;
-    public static final int HARDWARE_TYPE = 78;
+    public static final int HARDWARE_TYPE = 78; // to be used with DEVICE_OBJECT
+    public static final int MAX_ROUTED_APDU_LENGTH = 58; // to be used with ADDRESS_TABLE_OBJECT, renamed due to name
+                                                         // conflict in standard (PID.MAX_APDULENGTH used with
+                                                         // DEVICE_OBJECT)
 }
diff --git a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/handler/Firmware.java b/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/handler/Firmware.java
deleted file mode 100644 (file)
index 041cc8e..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/**
- * Copyright (c) 2010-2023 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.knx.internal.handler;
-
-/**
- * Enumeration containing the firmware types.
- *
- * @author Karel Goderis - Initial contribution
- */
-public enum Firmware {
-    F0(0, "BCU 1, BCU 2, BIM M113"),
-    F1(1, "Unidirectional devices"),
-    F3(3, "Property based device management"),
-    F7(7, "BIM M112"),
-    F8(8, "IR Decoder, TP1 legacy"),
-    F9(9, "Repeater, Coupler");
-
-    private int code;
-    private String name;
-
-    private Firmware(int code, String name) {
-        this.code = code;
-        this.name = name;
-    }
-
-    @Override
-    public String toString() {
-        return name;
-    }
-
-    public static String getName(int code) {
-        for (Firmware c : Firmware.values()) {
-            if (c.code == code) {
-                return c.name;
-            }
-        }
-        return null;
-    }
-}
index 97d46ad214254825199f9fcde738330475e03e8e..455280d10cd7e1c4f847e7ff6fdfd96df94a1922 100644 (file)
@@ -42,6 +42,7 @@ public enum Manufacturer {
     M30(30, "Feller"),
     M32(32, "DEHN & SÖHNE"),
     M33(33, "CRABTREE"),
+    M34(34, "eVoKNX"),
     M36(36, "Paul Hochköpper"),
     M37(37, "Altenburger Electronic"),
     M41(41, "Grässlin"),
@@ -321,7 +322,8 @@ public enum Manufacturer {
     M356(356, "AYPRO Technology"),
     M357(357, "Hefei Ecolite Software"),
     M358(358, "Enno"),
-    M359(359, "Ohosure");
+    M359(359, "Ohosure"),
+    M373(373, "ZF Friedrichshafen AG");
 
     private int code;
     private String name;
@@ -342,6 +344,6 @@ public enum Manufacturer {
                 return c.name;
             }
         }
-        return "Unknown";
+        return "Unknown (" + code + ")";
     }
 }