]> git.basschouten.com Git - openhab-addons.git/commitdiff
Improve discovery (#16692)
authorJacob Laursen <jacob-github@vindvejr.dk>
Mon, 29 Apr 2024 22:39:30 +0000 (00:39 +0200)
committerGitHub <noreply@github.com>
Mon, 29 Apr 2024 22:39:30 +0000 (00:39 +0200)
Resolves #16690

Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
bundles/org.openhab.binding.denonmarantz/src/main/feature/feature.xml
bundles/org.openhab.binding.denonmarantz/src/main/java/org/openhab/binding/denonmarantz/internal/DenonMarantzBindingConstants.java
bundles/org.openhab.binding.denonmarantz/src/main/java/org/openhab/binding/denonmarantz/internal/discovery/DenonMarantzDiscoveryParticipant.java [deleted file]
bundles/org.openhab.binding.denonmarantz/src/main/java/org/openhab/binding/denonmarantz/internal/discovery/DenonMarantzMDNSDiscoveryParticipant.java [new file with mode: 0644]
bundles/org.openhab.binding.denonmarantz/src/main/java/org/openhab/binding/denonmarantz/internal/discovery/DenonMarantzUpnpDiscoveryParticipant.java [new file with mode: 0644]

index 335458623072af8cfc1044d7741e62fb6a819268..107a4f038269960312be52074cae2cdbebb2a65a 100644 (file)
@@ -4,6 +4,7 @@
 
        <feature name="openhab-binding-denonmarantz" description="Denon / Marantz Binding" version="${project.version}">
                <feature>openhab-runtime-base</feature>
+               <feature>openhab-transport-upnp</feature>
                <bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.denonmarantz/${project.version}</bundle>
        </feature>
 </features>
index 58ba6a97116daf782b0af5f3c915b0db8f1cbc77..8da35e9163669f00237a25a840b977e87b921aba 100644 (file)
@@ -30,6 +30,9 @@ public class DenonMarantzBindingConstants {
 
     public static final String BINDING_ID = "denonmarantz";
 
+    public static final String VENDOR_DENON = "Denon";
+    public static final String VENDOR_MARANTZ = "Marantz";
+
     // List of all Thing Type UIDs
     public static final ThingTypeUID THING_TYPE_AVR = new ThingTypeUID(BINDING_ID, "avr");
 
diff --git a/bundles/org.openhab.binding.denonmarantz/src/main/java/org/openhab/binding/denonmarantz/internal/discovery/DenonMarantzDiscoveryParticipant.java b/bundles/org.openhab.binding.denonmarantz/src/main/java/org/openhab/binding/denonmarantz/internal/discovery/DenonMarantzDiscoveryParticipant.java
deleted file mode 100644 (file)
index 1104609..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-/**
- * Copyright (c) 2010-2024 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.denonmarantz.internal.discovery;
-
-import static org.openhab.binding.denonmarantz.internal.DenonMarantzBindingConstants.*;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import javax.jmdns.ServiceInfo;
-
-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.thing.Thing;
-import org.openhab.core.thing.ThingTypeUID;
-import org.openhab.core.thing.ThingUID;
-import org.osgi.service.component.annotations.Component;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * @author Jan-Willem Veldhuis - Initial contribution
- *
- */
-@Component
-public class DenonMarantzDiscoveryParticipant implements MDNSDiscoveryParticipant {
-
-    private Logger logger = LoggerFactory.getLogger(DenonMarantzDiscoveryParticipant.class);
-
-    // Service type for 'Airplay enabled' receivers
-    private static final String RAOP_SERVICE_TYPE = "_raop._tcp.local.";
-
-    /**
-     * Match the serial number, vendor and model of the discovered AVR.
-     * Input is like "0006781D58B1@Marantz SR5008._raop._tcp.local."
-     * A Denon AVR serial (MAC address) starts with 0005CD
-     * A Marantz AVR serial (MAC address) starts with 000678
-     */
-    private static final Pattern DENON_MARANTZ_PATTERN = Pattern
-            .compile("^((?:0005CD|000678)[A-Z0-9]+)@(.+)\\._raop\\._tcp\\.local\\.$");
-
-    /**
-     * Denon AVRs have a MAC address / serial number starting with 0005CD
-     */
-    private static final String DENON_MAC_PREFIX = "0005CD";
-
-    /**
-     * Marantz AVRs have a MAC address / serial number starting with 000678
-     */
-    private static final String MARANTZ_MAC_PREFIX = "000678";
-
-    @Override
-    public Set<ThingTypeUID> getSupportedThingTypeUIDs() {
-        return Set.of(THING_TYPE_AVR);
-    }
-
-    @Override
-    public String getServiceType() {
-        return RAOP_SERVICE_TYPE;
-    }
-
-    @Override
-    public DiscoveryResult createResult(ServiceInfo serviceInfo) {
-        String qualifiedName = serviceInfo.getQualifiedName();
-        logger.debug("AVR found: {}", qualifiedName);
-        ThingUID thingUID = getThingUID(serviceInfo);
-        if (thingUID != null) {
-            Matcher matcher = DENON_MARANTZ_PATTERN.matcher(qualifiedName);
-            matcher.matches(); // we already know it matches, it was matched in getThingUID
-            String serial = matcher.group(1).toLowerCase();
-
-            /**
-             * The Vendor is not available from the mDNS result.
-             * We assign the Vendor based on our assumptions of the MAC address prefix.
-             */
-            String vendor = "";
-            if (serial.startsWith(MARANTZ_MAC_PREFIX)) {
-                vendor = "Marantz";
-            } else if (serial.startsWith(DENON_MAC_PREFIX)) {
-                vendor = "Denon";
-            }
-
-            // 'am=...' property describes the model name
-            String model = serviceInfo.getPropertyString("am");
-            String friendlyName = matcher.group(2).trim();
-
-            Map<String, Object> properties = new HashMap<>(2);
-
-            if (serviceInfo.getHostAddresses().length == 0) {
-                logger.debug("Could not determine IP address for the Denon/Marantz AVR");
-                return null;
-            }
-            String host = serviceInfo.getHostAddresses()[0];
-
-            logger.debug("IP Address: {}", host);
-
-            properties.put(PARAMETER_HOST, host);
-            properties.put(Thing.PROPERTY_SERIAL_NUMBER, serial);
-            properties.put(Thing.PROPERTY_VENDOR, vendor);
-            properties.put(Thing.PROPERTY_MODEL_ID, model);
-
-            String label = friendlyName + " (" + vendor + ' ' + model + ")";
-            return DiscoveryResultBuilder.create(thingUID).withProperties(properties).withLabel(label)
-                    .withRepresentationProperty(Thing.PROPERTY_SERIAL_NUMBER).build();
-
-        } else {
-            return null;
-        }
-    }
-
-    @Override
-    public ThingUID getThingUID(ServiceInfo service) {
-        Matcher matcher = DENON_MARANTZ_PATTERN.matcher(service.getQualifiedName());
-        if (matcher.matches()) {
-            logger.debug("This seems like a supported Denon/Marantz AVR!");
-            String serial = matcher.group(1).toLowerCase();
-            return new ThingUID(THING_TYPE_AVR, serial);
-        } else {
-            logger.trace("This discovered device is not supported by the DenonMarantz binding, ignoring..");
-        }
-        return null;
-    }
-}
diff --git a/bundles/org.openhab.binding.denonmarantz/src/main/java/org/openhab/binding/denonmarantz/internal/discovery/DenonMarantzMDNSDiscoveryParticipant.java b/bundles/org.openhab.binding.denonmarantz/src/main/java/org/openhab/binding/denonmarantz/internal/discovery/DenonMarantzMDNSDiscoveryParticipant.java
new file mode 100644 (file)
index 0000000..6632761
--- /dev/null
@@ -0,0 +1,139 @@
+/**
+ * Copyright (c) 2010-2024 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.denonmarantz.internal.discovery;
+
+import static org.openhab.binding.denonmarantz.internal.DenonMarantzBindingConstants.*;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.jmdns.ServiceInfo;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+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.thing.Thing;
+import org.openhab.core.thing.ThingTypeUID;
+import org.openhab.core.thing.ThingUID;
+import org.osgi.service.component.annotations.Component;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The {@link DenonMarantzMDNSDiscoveryParticipant} is responsible for discovering Denon/Marantz AV Receivers.
+ * It uses the central {@link org.openhab.core.config.discovery.mdns.MDNSDiscoveryParticipant}.
+ *
+ * @author Jan-Willem Veldhuis - Initial contribution
+ */
+@Component(configurationPid = "discovery.denonmarantz")
+@NonNullByDefault
+public class DenonMarantzMDNSDiscoveryParticipant implements MDNSDiscoveryParticipant {
+
+    private Logger logger = LoggerFactory.getLogger(DenonMarantzMDNSDiscoveryParticipant.class);
+
+    // Service type for 'Airplay enabled' receivers
+    private static final String RAOP_SERVICE_TYPE = "_raop._tcp.local.";
+
+    /**
+     * Match the serial number, vendor and model of the discovered AVR.
+     * Input is like "0006781D58B1@Marantz SR5008._raop._tcp.local."
+     * Older Denon AVR's serial (MAC address) starts with 0005CD
+     * Older Marantz AVR's serial (MAC address) starts with 000678
+     * Newer Denon AVR's can start with 000678 as well.
+     */
+    private static final Pattern DENON_MARANTZ_PATTERN = Pattern
+            .compile("^((?:0005CD|000678)[A-Z0-9]+)@(.+)\\._raop\\._tcp\\.local\\.$");
+
+    private static final String DENON_MODEL_PREFIX = "denon";
+    private static final String MARANTZ_MODEL_PREFIX = "marantz";
+
+    @Override
+    public Set<ThingTypeUID> getSupportedThingTypeUIDs() {
+        return Set.of(THING_TYPE_AVR);
+    }
+
+    @Override
+    public String getServiceType() {
+        return RAOP_SERVICE_TYPE;
+    }
+
+    @Override
+    @Nullable
+    public DiscoveryResult createResult(ServiceInfo serviceInfo) {
+        String qualifiedName = serviceInfo.getQualifiedName();
+        logger.debug("AVR found: {}", qualifiedName);
+        ThingUID thingUID = getThingUID(serviceInfo);
+        if (thingUID == null) {
+            return null;
+        }
+
+        Matcher matcher = DENON_MARANTZ_PATTERN.matcher(qualifiedName);
+        matcher.matches(); // we already know it matches, it was matched in getThingUID
+        String serial = matcher.group(1).toLowerCase();
+
+        // 'am=...' property describes the model name
+        String model = serviceInfo.getPropertyString("am");
+        String friendlyName = matcher.group(2).trim();
+
+        String vendor;
+        String modelLowerCase = model == null ? "" : model.toLowerCase();
+        if (modelLowerCase.startsWith(DENON_MODEL_PREFIX)) {
+            vendor = VENDOR_DENON;
+        } else if (modelLowerCase.startsWith(MARANTZ_MODEL_PREFIX)) {
+            vendor = VENDOR_MARANTZ;
+        } else {
+            vendor = null;
+        }
+
+        Map<String, Object> properties = new HashMap<>(4);
+
+        if (serviceInfo.getHostAddresses().length == 0) {
+            logger.debug("Could not determine IP address for the Denon/Marantz AVR");
+            return null;
+        }
+        String host = serviceInfo.getHostAddresses()[0];
+
+        logger.debug("IP Address: {}", host);
+
+        properties.put(PARAMETER_HOST, host);
+        if (vendor != null) {
+            properties.put(Thing.PROPERTY_VENDOR, vendor);
+        }
+        properties.put(Thing.PROPERTY_SERIAL_NUMBER, serial);
+        if (model != null) {
+            properties.put(Thing.PROPERTY_MODEL_ID, model);
+        }
+
+        return DiscoveryResultBuilder.create(thingUID).withProperties(properties).withLabel(friendlyName)
+                .withRepresentationProperty(Thing.PROPERTY_SERIAL_NUMBER).build();
+    }
+
+    @Override
+    @Nullable
+    public ThingUID getThingUID(ServiceInfo service) {
+        Matcher matcher = DENON_MARANTZ_PATTERN.matcher(service.getQualifiedName());
+        if (matcher.matches()) {
+            logger.debug("This seems like a supported Denon/Marantz AVR!");
+            String serial = matcher.group(1).toLowerCase();
+            return new ThingUID(THING_TYPE_AVR, serial);
+        } else {
+            logger.trace("This discovered device is not supported by the DenonMarantz binding, ignoring..");
+        }
+        return null;
+    }
+}
diff --git a/bundles/org.openhab.binding.denonmarantz/src/main/java/org/openhab/binding/denonmarantz/internal/discovery/DenonMarantzUpnpDiscoveryParticipant.java b/bundles/org.openhab.binding.denonmarantz/src/main/java/org/openhab/binding/denonmarantz/internal/discovery/DenonMarantzUpnpDiscoveryParticipant.java
new file mode 100644 (file)
index 0000000..6db4e55
--- /dev/null
@@ -0,0 +1,105 @@
+/**
+ * Copyright (c) 2010-2024 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.denonmarantz.internal.discovery;
+
+import static org.openhab.binding.denonmarantz.internal.DenonMarantzBindingConstants.*;
+
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.jupnp.model.meta.DeviceDetails;
+import org.jupnp.model.meta.RemoteDevice;
+import org.openhab.core.config.discovery.DiscoveryResult;
+import org.openhab.core.config.discovery.DiscoveryResultBuilder;
+import org.openhab.core.config.discovery.upnp.UpnpDiscoveryParticipant;
+import org.openhab.core.thing.Thing;
+import org.openhab.core.thing.ThingTypeUID;
+import org.openhab.core.thing.ThingUID;
+import org.osgi.service.component.annotations.Component;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The {@link DenonMarantzUpnpDiscoveryParticipant} is responsible for discovering Denon AV Receivers.
+ * It uses the central {@link org.openhab.core.config.discovery.upnp.internal.UpnpDiscoveryService}.
+ *
+ * @author Jacob Laursen - Initial contribution
+ */
+@Component(configurationPid = "discovery.denonmarantz")
+@NonNullByDefault
+public class DenonMarantzUpnpDiscoveryParticipant implements UpnpDiscoveryParticipant {
+
+    private Logger logger = LoggerFactory.getLogger(DenonMarantzUpnpDiscoveryParticipant.class);
+
+    @Override
+    public Set<ThingTypeUID> getSupportedThingTypeUIDs() {
+        return Set.of(THING_TYPE_AVR);
+    }
+
+    @Override
+    public @Nullable DiscoveryResult createResult(RemoteDevice device) {
+        DeviceDetails details = device.getDetails();
+
+        if (!VENDOR_DENON.equalsIgnoreCase(details.getManufacturerDetails().getManufacturer())) {
+            return null;
+        }
+
+        URL baseUrl = details.getBaseURL();
+        if (baseUrl == null) {
+            logger.debug("Discovered {}, but base URL is missing", device.getDisplayString());
+            return null;
+        }
+
+        String serialNumber = details.getSerialNumber();
+        if (serialNumber == null) {
+            logger.debug("Discovered {}, but serial number is missing", device.getDisplayString());
+            return null;
+        }
+
+        ThingUID thingUID = getThingUID(device);
+        if (thingUID == null) {
+            return null;
+        }
+
+        String host = baseUrl.getHost();
+        String model = details.getModelDetails().getModelName();
+
+        logger.debug("Discovered {}", device.getDisplayString());
+
+        Map<String, Object> properties = new HashMap<>(4);
+        properties.put(PARAMETER_HOST, host);
+        properties.put(Thing.PROPERTY_VENDOR, VENDOR_DENON);
+        properties.put(Thing.PROPERTY_MODEL_ID, model);
+        properties.put(Thing.PROPERTY_SERIAL_NUMBER, serialNumber.toLowerCase());
+
+        return DiscoveryResultBuilder.create(thingUID).withProperties(properties).withLabel(VENDOR_DENON + " " + model)
+                .withRepresentationProperty(Thing.PROPERTY_SERIAL_NUMBER).build();
+    }
+
+    @Override
+    public @Nullable ThingUID getThingUID(RemoteDevice device) {
+        DeviceDetails details = device.getDetails();
+        if (!VENDOR_DENON.equalsIgnoreCase(details.getManufacturerDetails().getManufacturer())) {
+            return null;
+        }
+        String serialNumber = details.getSerialNumber();
+        if (serialNumber == null) {
+            return null;
+        }
+        return new ThingUID(THING_TYPE_AVR, serialNumber.toLowerCase());
+    }
+}