From 7bd99df36425228629cb7cd956de74201f875338 Mon Sep 17 00:00:00 2001 From: Holger Friedrich Date: Tue, 7 Mar 2023 19:31:39 +0100 Subject: [PATCH] [knx] Improve reading of device properties (#14050) * [knx] Improve reading of device properties * [knx] DD2 logging only in debug mode Signed-off-by: Holger Friedrich --- .../knx/internal/KNXBindingConstants.java | 17 +- .../knx/internal/client/DeviceInfoClient.java | 9 +- .../internal/client/DeviceInfoClientImpl.java | 10 +- .../knx/internal/client/DeviceInspector.java | 279 +++++++++++++++--- .../knx/internal/handler/DeviceConstants.java | 6 +- .../knx/internal/handler/Firmware.java | 49 --- .../knx/internal/handler/Manufacturer.java | 6 +- 7 files changed, 264 insertions(+), 112 deletions(-) delete mode 100644 bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/handler/Firmware.java diff --git a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/KNXBindingConstants.java b/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/KNXBindingConstants.java index 948aae7c8..b2557e545 100644 --- a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/KNXBindingConstants.java +++ b/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/KNXBindingConstants.java @@ -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"; diff --git a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/client/DeviceInfoClient.java b/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/client/DeviceInfoClient.java index c46f26db9..32677057d 100644 --- a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/client/DeviceInfoClient.java +++ b/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/client/DeviceInfoClient.java @@ -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(); } diff --git a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/client/DeviceInfoClientImpl.java b/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/client/DeviceInfoClientImpl.java index 5c6724824..b49795614 100644 --- a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/client/DeviceInfoClientImpl.java +++ b/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/client/DeviceInfoClientImpl.java @@ -49,7 +49,7 @@ public class DeviceInfoClientImpl implements DeviceInfoClient { } private byte @Nullable [] readFromManagementClient(String task, long timeout, IndividualAddress address, - ReadFunction function) { + ReadFunction 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); diff --git a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/client/DeviceInspector.java b/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/client/DeviceInspector.java index 488de9832..4e0f05da6 100644 --- a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/client/DeviceInspector.java +++ b/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/client/DeviceInspector.java @@ -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 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 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 readDeviceProperties(IndividualAddress address) throws InterruptedException { Map 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), " "); - Thread.sleep(OPERATION_INTERVAL); - String firmwareRevision = Integer.toString(toUnsigned(getClient().readDeviceProperties(address, - DEVICE_OBJECT, PID.FIRMWARE_REVISION, 1, 1, false, OPERATION_TIMEOUT))); + String manufacturerID = Manufacturer.getName(toUnsigned(getClient().readDeviceProperties(address, + DEVICE_OBJECT, PID.MANUFACTURER_ID, 1, 1, false, OPERATION_TIMEOUT))); - ret.put(MANUFACTURER_NAME, manufacturerID); - if (serialNo != null) { - ret.put(MANUFACTURER_SERIAL_NO, serialNo); + 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)); + } } - if (hardwareType != null) { - ret.put(MANUFACTURER_HARDWARE_TYPE, hardwareType); - } - 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) { + throw e; + } catch (Exception ignore) { + // allowed to fail, optional } - } catch (InterruptedException e) { - logger.debug("Interrupted while fetching the device description for a device '{}' : {}", address, - e.getMessage()); + + // 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); + 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 + } + } + + 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); + } + } + + // 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); + } + 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 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 readDeviceDescription(IndividualAddress address) throws InterruptedException { Map ret = new HashMap<>(); byte[] data = getClient().readDeviceDescription(address, 0, false, OPERATION_TIMEOUT); if (data != null) { - final DD0 dd = DeviceDescriptor.DD0.from(data); + try { + 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())); + 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 + ")"; + } + } } diff --git a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/handler/DeviceConstants.java b/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/handler/DeviceConstants.java index 391adb491..82623aa34 100644 --- a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/handler/DeviceConstants.java +++ b/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/handler/DeviceConstants.java @@ -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 index 041cc8e96..000000000 --- a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/handler/Firmware.java +++ /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; - } -} diff --git a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/handler/Manufacturer.java b/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/handler/Manufacturer.java index 97d46ad21..455280d10 100644 --- a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/handler/Manufacturer.java +++ b/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/handler/Manufacturer.java @@ -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 + ")"; } }