From a93f3d7d90f7d0a8c97edfd8b065d26e6afa2ead Mon Sep 17 00:00:00 2001 From: Andrew Fiddian-Green Date: Wed, 27 Dec 2023 17:27:40 +0000 Subject: [PATCH] Add-on suggestion finder for USB devices (#3922) Also-by: Holger Friedrich Signed-off-by: Andrew Fiddian-Green --- bom/openhab-core/pom.xml | 6 + .../addon/process/ProcessAddonFinder.java | 2 +- .../discovery/addon/upnp/UpnpAddonFinder.java | 2 +- .../.classpath | 29 +++ .../.project | 23 +++ .../NOTICE | 14 ++ .../pom.xml | 35 ++++ .../discovery/addon/usb/UsbAddonFinder.java | 186 ++++++++++++++++++ .../addon/usb/UsbAddonFinderTests.java | 101 ++++++++++ .../discovery/addon/AddonFinderConstants.java | 15 +- .../internal/Ser2NetUsbSerialDiscovery.java | 3 +- .../Ser2NetUsbSerialDiscoveryTest.java | 6 +- .../usbserial/UsbSerialDeviceInformation.java | 26 ++- .../main/resources/OH-INF/config/addons.xml | 5 + .../resources/OH-INF/i18n/addons.properties | 2 + bundles/pom.xml | 1 + .../openhab-core/src/main/feature/feature.xml | 7 + 17 files changed, 451 insertions(+), 12 deletions(-) create mode 100644 bundles/org.openhab.core.config.discovery.addon.usb/.classpath create mode 100644 bundles/org.openhab.core.config.discovery.addon.usb/.project create mode 100644 bundles/org.openhab.core.config.discovery.addon.usb/NOTICE create mode 100644 bundles/org.openhab.core.config.discovery.addon.usb/pom.xml create mode 100644 bundles/org.openhab.core.config.discovery.addon.usb/src/main/java/org/openhab/core/config/discovery/addon/usb/UsbAddonFinder.java create mode 100644 bundles/org.openhab.core.config.discovery.addon.usb/src/test/java/org/openhab/core/config/discovery/addon/usb/UsbAddonFinderTests.java diff --git a/bom/openhab-core/pom.xml b/bom/openhab-core/pom.xml index 5cf3eefdb23..786fc9df575 100644 --- a/bom/openhab-core/pom.xml +++ b/bom/openhab-core/pom.xml @@ -334,6 +334,12 @@ ${project.version} compile + + org.openhab.core.bundles + org.openhab.core.config.discovery.addon.usb + ${project.version} + compile + org.openhab.core.bundles org.openhab.core.config.discovery.mdns diff --git a/bundles/org.openhab.core.config.discovery.addon.process/src/main/java/org/openhab/core/config/discovery/addon/process/ProcessAddonFinder.java b/bundles/org.openhab.core.config.discovery.addon.process/src/main/java/org/openhab/core/config/discovery/addon/process/ProcessAddonFinder.java index 6c7543daf6d..decd6972965 100644 --- a/bundles/org.openhab.core.config.discovery.addon.process/src/main/java/org/openhab/core/config/discovery/addon/process/ProcessAddonFinder.java +++ b/bundles/org.openhab.core.config.discovery.addon.process/src/main/java/org/openhab/core/config/discovery/addon/process/ProcessAddonFinder.java @@ -105,7 +105,7 @@ public Set getSuggestedAddons() { } // now check if a process matches the pattern defined in addon.xml - logger.debug("Checking candidate: {}", candidate.getUID()); + logger.trace("Checking candidate: {}", candidate.getUID()); for (AddonMatchProperty command : commands) { logger.trace("Candidate {}, pattern \"{}\"", candidate.getUID(), command.getRegex()); diff --git a/bundles/org.openhab.core.config.discovery.addon.upnp/src/main/java/org/openhab/core/config/discovery/addon/upnp/UpnpAddonFinder.java b/bundles/org.openhab.core.config.discovery.addon.upnp/src/main/java/org/openhab/core/config/discovery/addon/upnp/UpnpAddonFinder.java index 68925b6ce67..8ef19064bf6 100644 --- a/bundles/org.openhab.core.config.discovery.addon.upnp/src/main/java/org/openhab/core/config/discovery/addon/upnp/UpnpAddonFinder.java +++ b/bundles/org.openhab.core.config.discovery.addon.upnp/src/main/java/org/openhab/core/config/discovery/addon/upnp/UpnpAddonFinder.java @@ -188,7 +188,7 @@ && propertyMatches(matchProperties, MODEL_URI, modelURI) && propertyMatches(matchProperties, SERIAL_NUMBER, serialNumber) && propertyMatches(matchProperties, FRIENDLY_NAME, friendlyName)) { result.add(candidate); - logger.debug("Suggested addon found: {}", candidate.getUID()); + logger.debug("Suggested add-on found: {}", candidate.getUID()); break; } } diff --git a/bundles/org.openhab.core.config.discovery.addon.usb/.classpath b/bundles/org.openhab.core.config.discovery.addon.usb/.classpath new file mode 100644 index 00000000000..d3d6b3c11b6 --- /dev/null +++ b/bundles/org.openhab.core.config.discovery.addon.usb/.classpath @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bundles/org.openhab.core.config.discovery.addon.usb/.project b/bundles/org.openhab.core.config.discovery.addon.usb/.project new file mode 100644 index 00000000000..bf360c9c71e --- /dev/null +++ b/bundles/org.openhab.core.config.discovery.addon.usb/.project @@ -0,0 +1,23 @@ + + + org.openhab.core.config.discovery.addon.usb + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.m2e.core.maven2Nature + org.eclipse.jdt.core.javanature + + diff --git a/bundles/org.openhab.core.config.discovery.addon.usb/NOTICE b/bundles/org.openhab.core.config.discovery.addon.usb/NOTICE new file mode 100644 index 00000000000..6c17d0d8a45 --- /dev/null +++ b/bundles/org.openhab.core.config.discovery.addon.usb/NOTICE @@ -0,0 +1,14 @@ +This content is produced and maintained by the openHAB project. + +* Project home: https://www.openhab.org + +== Declared Project Licenses + +This program and the accompanying materials are made available under the terms +of the Eclipse Public License 2.0 which is available at +https://www.eclipse.org/legal/epl-2.0/. + +== Source Code + +https://github.com/openhab/openhab-core + diff --git a/bundles/org.openhab.core.config.discovery.addon.usb/pom.xml b/bundles/org.openhab.core.config.discovery.addon.usb/pom.xml new file mode 100644 index 00000000000..7ca3bcafc8d --- /dev/null +++ b/bundles/org.openhab.core.config.discovery.addon.usb/pom.xml @@ -0,0 +1,35 @@ + + + + 4.0.0 + + + org.openhab.core.bundles + org.openhab.core.reactor.bundles + 4.2.0-SNAPSHOT + + + org.openhab.core.config.discovery.addon.usb + + openHAB Core :: Bundles :: USB Suggested Add-on Finder + + + + org.openhab.core.bundles + org.openhab.core.config.discovery.addon + ${project.version} + + + org.openhab.core.bundles + org.openhab.core.addon + ${project.version} + + + org.openhab.core.bundles + org.openhab.core.config.discovery.usbserial + ${project.version} + + + + diff --git a/bundles/org.openhab.core.config.discovery.addon.usb/src/main/java/org/openhab/core/config/discovery/addon/usb/UsbAddonFinder.java b/bundles/org.openhab.core.config.discovery.addon.usb/src/main/java/org/openhab/core/config/discovery/addon/usb/UsbAddonFinder.java new file mode 100644 index 00000000000..2015a1c8914 --- /dev/null +++ b/bundles/org.openhab.core.config.discovery.addon.usb/src/main/java/org/openhab/core/config/discovery/addon/usb/UsbAddonFinder.java @@ -0,0 +1,186 @@ +/** + * 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.core.config.discovery.addon.usb; + +import static org.openhab.core.config.discovery.addon.AddonFinderConstants.SERVICE_NAME_USB; +import static org.openhab.core.config.discovery.addon.AddonFinderConstants.SERVICE_TYPE_USB; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.addon.AddonDiscoveryMethod; +import org.openhab.core.addon.AddonInfo; +import org.openhab.core.config.discovery.addon.AddonFinder; +import org.openhab.core.config.discovery.addon.BaseAddonFinder; +import org.openhab.core.config.discovery.usbserial.UsbSerialDeviceInformation; +import org.openhab.core.config.discovery.usbserial.UsbSerialDiscovery; +import org.openhab.core.config.discovery.usbserial.UsbSerialDiscoveryListener; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This is a {@link USBAddonFinder} for finding suggested add-ons related to USB devices. + *

+ * It supports the following values for the 'match-property' 'name' element: + *

  • product - match on the product description text + *
  • manufacturer - match on the device manufacturer text + *
  • chipId - match on the chip vendor id plus product id + *
  • remote - match on whether the device is connected remotely or locally + * + * @author Andrew Fiddian-Green - Initial contribution + */ +@NonNullByDefault +@Component(service = AddonFinder.class, name = UsbAddonFinder.SERVICE_NAME) +public class UsbAddonFinder extends BaseAddonFinder implements UsbSerialDiscoveryListener { + + public static final String SERVICE_TYPE = SERVICE_TYPE_USB; + public static final String SERVICE_NAME = SERVICE_NAME_USB; + + /* + * Supported 'match-property' names + */ + public static final String PRODUCT = "product"; + public static final String MANUFACTURER = "manufacturer"; + public static final String CHIP_ID = "chipId"; + public static final String REMOTE = "remote"; + + public static final Set SUPPORTED_PROPERTIES = Set.of(PRODUCT, MANUFACTURER, CHIP_ID, REMOTE); + + private final Logger logger = LoggerFactory.getLogger(UsbAddonFinder.class); + private final Set usbSerialDiscoveries = new CopyOnWriteArraySet<>(); + private final Map usbDeviceInformations = new ConcurrentHashMap<>(); + + @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC) + protected void addUsbSerialDiscovery(UsbSerialDiscovery usbSerialDiscovery) { + usbSerialDiscoveries.add(usbSerialDiscovery); + usbSerialDiscovery.registerDiscoveryListener(this); + usbSerialDiscovery.doSingleScan(); + } + + protected synchronized void removeUsbSerialDiscovery(UsbSerialDiscovery usbSerialDiscovery) { + usbSerialDiscovery.unregisterDiscoveryListener(this); + usbSerialDiscoveries.remove(usbSerialDiscovery); + } + + @Override + public Set getSuggestedAddons() { + Set result = new HashSet<>(); + for (AddonInfo candidate : addonCandidates) { + for (AddonDiscoveryMethod method : candidate.getDiscoveryMethods().stream() + .filter(method -> SERVICE_TYPE.equals(method.getServiceType())).toList()) { + Map matchProperties = method.getMatchProperties().stream() + .collect(Collectors.toMap(property -> property.getName(), property -> property.getPattern())); + + Set propertyNames = new HashSet<>(matchProperties.keySet()); + propertyNames.removeAll(SUPPORTED_PROPERTIES); + + if (!propertyNames.isEmpty()) { + logger.warn("Add-on '{}' addon.xml file contains unsupported 'match-property' [{}]", + candidate.getUID(), String.join(",", propertyNames)); + break; + } + + logger.trace("Checking candidate: {}", candidate.getUID()); + for (UsbSerialDeviceInformation device : usbDeviceInformations.values()) { + logger.trace("Checking device: {}", device); + + if (propertyMatches(matchProperties, PRODUCT, device.getProduct()) + && propertyMatches(matchProperties, MANUFACTURER, device.getManufacturer()) + && propertyMatches(matchProperties, CHIP_ID, + getChipId(device.getVendorId(), device.getProductId())) + && propertyMatches(matchProperties, REMOTE, String.valueOf(device.getRemote()))) { + result.add(candidate); + logger.debug("Suggested add-on found: {}", candidate.getUID()); + break; + } + } + } + } + return result; + } + + private String getChipId(int vendorId, int productId) { + return String.format("%04x:%04x", vendorId, productId); + } + + @Override + public String getServiceName() { + return SERVICE_NAME; + } + + /** + * Create a unique 33 bit integer map hash key comprising the remote flag in the upper bit, the vendorId in the + * middle 16 bits, and the productId in the lower 16 bits. + */ + private long keyOf(UsbSerialDeviceInformation deviceInfo) { + return (deviceInfo.getRemote() ? 0x1_0000_0000L : 0) + (deviceInfo.getVendorId() * 0x1_0000L) + + deviceInfo.getProductId(); + } + + /** + * Add the discovered USB device information record to our internal map. If there is already an entry in the map + * then merge the two sets of data. + * + * @param discoveredInfo the newly discovered USB device information. + */ + @Override + public void usbSerialDeviceDiscovered(UsbSerialDeviceInformation discoveredInfo) { + UsbSerialDeviceInformation targetInfo = discoveredInfo; + UsbSerialDeviceInformation existingInfo = usbDeviceInformations.get(keyOf(targetInfo)); + + if (existingInfo != null) { + boolean isMerging = false; + String product = existingInfo.getProduct(); + if (product != null) { + product = discoveredInfo.getProduct(); + isMerging = true; + } + String manufacturer = existingInfo.getManufacturer(); + if (manufacturer != null) { + manufacturer = discoveredInfo.getManufacturer(); + isMerging = true; + } + String serialNumber = existingInfo.getSerialNumber(); + if (serialNumber != null) { + serialNumber = discoveredInfo.getSerialNumber(); + isMerging = true; + } + boolean remote = existingInfo.getRemote(); + if (remote == discoveredInfo.getRemote()) { + isMerging = true; + } + if (isMerging) { + targetInfo = new UsbSerialDeviceInformation(discoveredInfo.getVendorId(), discoveredInfo.getProductId(), + serialNumber, manufacturer, product, discoveredInfo.getInterfaceNumber(), + discoveredInfo.getInterfaceDescription(), discoveredInfo.getSerialPort()).setRemote(remote); + } + } + + usbDeviceInformations.put(keyOf(targetInfo), targetInfo); + } + + @Override + public void usbSerialDeviceRemoved(UsbSerialDeviceInformation removedInfo) { + usbDeviceInformations.remove(keyOf(removedInfo)); + } +} diff --git a/bundles/org.openhab.core.config.discovery.addon.usb/src/test/java/org/openhab/core/config/discovery/addon/usb/UsbAddonFinderTests.java b/bundles/org.openhab.core.config.discovery.addon.usb/src/test/java/org/openhab/core/config/discovery/addon/usb/UsbAddonFinderTests.java new file mode 100644 index 00000000000..ad8a305786c --- /dev/null +++ b/bundles/org.openhab.core.config.discovery.addon.usb/src/test/java/org/openhab/core/config/discovery/addon/usb/UsbAddonFinderTests.java @@ -0,0 +1,101 @@ +/** + * 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.core.config.discovery.addon.usb; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestInstance.Lifecycle; +import org.openhab.core.addon.AddonDiscoveryMethod; +import org.openhab.core.addon.AddonInfo; +import org.openhab.core.addon.AddonMatchProperty; +import org.openhab.core.config.discovery.usbserial.UsbSerialDeviceInformation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ch.qos.logback.classic.Level; + +/** + * This contains tests for the {@link UsbAddonFinder} class. + * + * @author Andrew Fiddian-Green - Initial contribution + */ +@NonNullByDefault +@TestInstance(Lifecycle.PER_CLASS) +class UsbAddonFinderTests { + + @Test + void testSuggestionFinder() { + Logger root = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME); + ((ch.qos.logback.classic.Logger) root).setLevel(Level.ERROR); + + AddonMatchProperty matchProperty = new AddonMatchProperty("product", "(?i).*zigbee.*"); + + AddonDiscoveryMethod discoveryMethod = new AddonDiscoveryMethod(); + discoveryMethod.setMatchProperties(List.of(matchProperty)).setServiceType("usb"); + + List addons = new ArrayList<>(); + addons.add(AddonInfo.builder("id", "binding").withName("name").withDescription("description") + .withDiscoveryMethods(List.of(discoveryMethod)).build()); + + UsbAddonFinder finder = new UsbAddonFinder(); + finder.setAddonCandidates(addons); + + finder.usbSerialDeviceDiscovered( + new UsbSerialDeviceInformation(0x123, 0x234, null, null, null, 0, "n/a", "n/a")); + + Set suggestions = finder.getSuggestedAddons(); + assertNotNull(suggestions); + assertTrue(suggestions.isEmpty()); + + finder.usbSerialDeviceDiscovered( + new UsbSerialDeviceInformation(0x345, 0x456, null, null, "some zigBEE product", 0, "n/a", "n/a")); + + suggestions = finder.getSuggestedAddons(); + assertNotNull(suggestions); + assertFalse(suggestions.isEmpty()); + } + + @Test + void testBadSyntax() { + Logger root = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME); + ((ch.qos.logback.classic.Logger) root).setLevel(Level.ERROR); + + AddonMatchProperty matchProperty = new AddonMatchProperty("aardvark", "(?i).*zigbee.*"); + + AddonDiscoveryMethod discoveryMethod = new AddonDiscoveryMethod(); + discoveryMethod.setMatchProperties(List.of(matchProperty)).setServiceType("usb"); + + List addons = new ArrayList<>(); + addons.add(AddonInfo.builder("id", "binding").withName("name").withDescription("description") + .withDiscoveryMethods(List.of(discoveryMethod)).build()); + + UsbAddonFinder finder = new UsbAddonFinder(); + finder.setAddonCandidates(addons); + + finder.usbSerialDeviceDiscovered( + new UsbSerialDeviceInformation(0x123, 0x234, null, null, null, 0, "n/a", "n/a")); + + Set suggestions = finder.getSuggestedAddons(); + assertNotNull(suggestions); + assertTrue(suggestions.isEmpty()); + } +} diff --git a/bundles/org.openhab.core.config.discovery.addon/src/main/java/org/openhab/core/config/discovery/addon/AddonFinderConstants.java b/bundles/org.openhab.core.config.discovery.addon/src/main/java/org/openhab/core/config/discovery/addon/AddonFinderConstants.java index d282be84b54..a72764f6ce4 100644 --- a/bundles/org.openhab.core.config.discovery.addon/src/main/java/org/openhab/core/config/discovery/addon/AddonFinderConstants.java +++ b/bundles/org.openhab.core.config.discovery.addon/src/main/java/org/openhab/core/config/discovery/addon/AddonFinderConstants.java @@ -43,10 +43,17 @@ public class AddonFinderConstants { public static final String SERVICE_NAME_UPNP = SERVICE_TYPE_UPNP + ADDON_SUGGESTION_FINDER; public static final String FEATURE_UPNP = ADDON_SUGGESTION_FINDER_FEATURE + SERVICE_TYPE_UPNP; - public static final List SUGGESTION_FINDERS = List.of(SERVICE_NAME_IP, SERVICE_NAME_MDNS, - SERVICE_NAME_UPNP); + public static final String SERVICE_TYPE_USB = "usb"; + public static final String CFG_FINDER_USB = "suggestionFinderUsb"; + public static final String SERVICE_NAME_USB = SERVICE_TYPE_USB + ADDON_SUGGESTION_FINDER; + public static final String FEATURE_USB = ADDON_SUGGESTION_FINDER_FEATURE + SERVICE_TYPE_USB; + + public static final List SUGGESTION_FINDERS = List.of(SERVICE_NAME_IP, SERVICE_NAME_MDNS, SERVICE_NAME_UPNP, + SERVICE_NAME_USB); + public static final Map SUGGESTION_FINDER_CONFIGS = Map.of(SERVICE_NAME_IP, CFG_FINDER_IP, - SERVICE_NAME_MDNS, CFG_FINDER_MDNS, SERVICE_NAME_UPNP, CFG_FINDER_UPNP); + SERVICE_NAME_MDNS, CFG_FINDER_MDNS, SERVICE_NAME_UPNP, CFG_FINDER_UPNP, SERVICE_NAME_USB, CFG_FINDER_USB); + public static final Map SUGGESTION_FINDER_FEATURES = Map.of(SERVICE_NAME_IP, FEATURE_IP, - SERVICE_NAME_MDNS, FEATURE_MDNS, SERVICE_NAME_UPNP, FEATURE_UPNP); + SERVICE_NAME_MDNS, FEATURE_MDNS, SERVICE_NAME_UPNP, FEATURE_UPNP, SERVICE_NAME_USB, FEATURE_USB); } diff --git a/bundles/org.openhab.core.config.discovery.usbserial.ser2net/src/main/java/org/openhab/core/config/discovery/usbserial/ser2net/internal/Ser2NetUsbSerialDiscovery.java b/bundles/org.openhab.core.config.discovery.usbserial.ser2net/src/main/java/org/openhab/core/config/discovery/usbserial/ser2net/internal/Ser2NetUsbSerialDiscovery.java index c7a17b0d2b6..2cf0e0e71ba 100644 --- a/bundles/org.openhab.core.config.discovery.usbserial.ser2net/src/main/java/org/openhab/core/config/discovery/usbserial/ser2net/internal/Ser2NetUsbSerialDiscovery.java +++ b/bundles/org.openhab.core.config.discovery.usbserial.ser2net/src/main/java/org/openhab/core/config/discovery/usbserial/ser2net/internal/Ser2NetUsbSerialDiscovery.java @@ -198,7 +198,8 @@ private Optional createUsbSerialDeviceInformation(Se serviceInfo.getPort()); UsbSerialDeviceInformation deviceInfo = new UsbSerialDeviceInformation(vendorId, productId, serialNumber, - manufacturer, product, interfaceNumber, interfaceDescription, serialPortName); + manufacturer, product, interfaceNumber, interfaceDescription, serialPortName).setRemote(true); + logger.debug("Created {} based on {}", deviceInfo, serviceInfo); return Optional.of(deviceInfo); } catch (NumberFormatException e) { diff --git a/bundles/org.openhab.core.config.discovery.usbserial.ser2net/src/test/java/org/openhab/core/config/discovery/usbserial/ser2net/internal/Ser2NetUsbSerialDiscoveryTest.java b/bundles/org.openhab.core.config.discovery.usbserial.ser2net/src/test/java/org/openhab/core/config/discovery/usbserial/ser2net/internal/Ser2NetUsbSerialDiscoveryTest.java index 48dae85d310..538b828d53f 100644 --- a/bundles/org.openhab.core.config.discovery.usbserial.ser2net/src/test/java/org/openhab/core/config/discovery/usbserial/ser2net/internal/Ser2NetUsbSerialDiscoveryTest.java +++ b/bundles/org.openhab.core.config.discovery.usbserial.ser2net/src/test/java/org/openhab/core/config/discovery/usbserial/ser2net/internal/Ser2NetUsbSerialDiscoveryTest.java @@ -61,11 +61,11 @@ public class Ser2NetUsbSerialDiscoveryTest { private @NonNullByDefault({}) Ser2NetUsbSerialDiscovery discovery; private UsbSerialDeviceInformation usb1 = new UsbSerialDeviceInformation(0x100, 0x111, "serial1", "manufacturer1", - "product1", 0x1, "interface1", "rfc2217://1.1.1.1:1000"); + "product1", 0x1, "interface1", "rfc2217://1.1.1.1:1000").setRemote(true); private UsbSerialDeviceInformation usb2 = new UsbSerialDeviceInformation(0x200, 0x222, "serial2", "manufacturer2", - "product2", 0x2, "interface2", "rfc2217://[0:0:0:0:0:ffff:0202:0202]:2222"); + "product2", 0x2, "interface2", "rfc2217://[0:0:0:0:0:ffff:0202:0202]:2222").setRemote(true); private UsbSerialDeviceInformation usb3 = new UsbSerialDeviceInformation(0x300, 0x333, null, null, null, 0x3, null, - "rfc2217://123.222.100.000:3030"); + "rfc2217://123.222.100.000:3030").setRemote(true); @BeforeEach public void beforeEach() { diff --git a/bundles/org.openhab.core.config.discovery.usbserial/src/main/java/org/openhab/core/config/discovery/usbserial/UsbSerialDeviceInformation.java b/bundles/org.openhab.core.config.discovery.usbserial/src/main/java/org/openhab/core/config/discovery/usbserial/UsbSerialDeviceInformation.java index 60ed8b2714d..c446ad00c8f 100644 --- a/bundles/org.openhab.core.config.discovery.usbserial/src/main/java/org/openhab/core/config/discovery/usbserial/UsbSerialDeviceInformation.java +++ b/bundles/org.openhab.core.config.discovery.usbserial/src/main/java/org/openhab/core/config/discovery/usbserial/UsbSerialDeviceInformation.java @@ -45,6 +45,8 @@ public class UsbSerialDeviceInformation { private final String serialPort; + private boolean remote = false; + public UsbSerialDeviceInformation(int vendorId, int productId, @Nullable String serialNumber, @Nullable String manufacturer, @Nullable String product, int interfaceNumber, @Nullable String interfaceDescription, String serialPort) { @@ -118,6 +120,21 @@ public String getSerialPort() { return serialPort; } + /** + * @return if the serial device is remote or local. + */ + public boolean getRemote() { + return remote; + } + + /** + * Set the remote flag + */ + public UsbSerialDeviceInformation setRemote(boolean remote) { + this.remote = remote; + return this; + } + @SuppressWarnings("null") @Override public int hashCode() { @@ -131,6 +148,7 @@ public int hashCode() { result = prime * result + ((product == null) ? 0 : product.hashCode()); result = prime * result + ((serialNumber == null) ? 0 : serialNumber.hashCode()); result = prime * result + ((interfaceDescription == null) ? 0 : interfaceDescription.hashCode()); + result = prime * result + (remote ? 1 : 0); return result; } @@ -180,6 +198,10 @@ public boolean equals(@Nullable Object obj) { return false; } + if (remote != other.remote) { + return false; + } + return true; } @@ -187,8 +209,8 @@ public boolean equals(@Nullable Object obj) { public String toString() { return String.format( "UsbSerialDeviceInformation [vendorId=0x%04X, productId=0x%04X, serialNumber=%s, manufacturer=%s, " - + "product=%s, interfaceNumber=0x%02X, interfaceDescription=%s, serialPort=%s]", + + "product=%s, interfaceNumber=0x%02X, interfaceDescription=%s, serialPort=%s, remote=%b]", vendorId, productId, serialNumber, manufacturer, product, interfaceNumber, interfaceDescription, - serialPort); + serialPort, remote); } } diff --git a/bundles/org.openhab.core/src/main/resources/OH-INF/config/addons.xml b/bundles/org.openhab.core/src/main/resources/OH-INF/config/addons.xml index cbd0802400e..752351223b7 100644 --- a/bundles/org.openhab.core/src/main/resources/OH-INF/config/addons.xml +++ b/bundles/org.openhab.core/src/main/resources/OH-INF/config/addons.xml @@ -33,6 +33,11 @@ true Use IP network discovery broadcasts to suggest add-ons. Enabling/disabling may take up to 1 minute. + + + true + + Scan connected USB devices to suggest add-ons. Enabling/disabling may take up to 1 minute. true diff --git a/bundles/org.openhab.core/src/main/resources/OH-INF/i18n/addons.properties b/bundles/org.openhab.core/src/main/resources/OH-INF/i18n/addons.properties index d63c1ac73a5..0d22f9d7de4 100644 --- a/bundles/org.openhab.core/src/main/resources/OH-INF/i18n/addons.properties +++ b/bundles/org.openhab.core/src/main/resources/OH-INF/i18n/addons.properties @@ -8,5 +8,7 @@ system.config.addons.suggestionFinderMdns.label = mDNS Suggestion Finder system.config.addons.suggestionFinderMdns.description = Use mDNS network scan to suggest add-ons. Enabling/disabling may take up to 1 minute. system.config.addons.suggestionFinderUpnp.label = UPnP Suggestion Finder system.config.addons.suggestionFinderUpnp.description = Use UPnP network scan to suggest add-ons. Enabling/disabling may take up to 1 minute. +system.config.addons.suggestionFinderUsb.label = USB Suggestion Finder +system.config.addons.suggestionFinderUsb.description = Scan connected USB devices to suggest add-ons. Enabling/disabling may take up to 1 minute. service.system.addons.label = Add-on Management diff --git a/bundles/pom.xml b/bundles/pom.xml index 3d4b79ecd9d..5035de7e1a7 100644 --- a/bundles/pom.xml +++ b/bundles/pom.xml @@ -35,6 +35,7 @@ org.openhab.core.config.discovery.addon.mdns org.openhab.core.config.discovery.addon.process org.openhab.core.config.discovery.addon.upnp + org.openhab.core.config.discovery.addon.usb org.openhab.core.config.discovery.mdns org.openhab.core.config.discovery.usbserial org.openhab.core.config.discovery.usbserial.linuxsysfs diff --git a/features/karaf/openhab-core/src/main/feature/feature.xml b/features/karaf/openhab-core/src/main/feature/feature.xml index 44e3eb37a79..a5062604397 100644 --- a/features/karaf/openhab-core/src/main/feature/feature.xml +++ b/features/karaf/openhab-core/src/main/feature/feature.xml @@ -98,6 +98,13 @@ openhab.tp-jupnp + + openhab-core-base + openhab-core-config-discovery-addon + openhab-transport-serial + mvn:org.openhab.core.bundles/org.openhab.core.config.discovery.addon.usb/${project.version} + + kar openhab-core-base