mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
Improve discovery (#16692)
Resolves #16690 Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk> Signed-off-by: Ciprian Pascu <contact@ciprianpascu.ro>
This commit is contained in:
parent
2479529eab
commit
5645dfb73b
@ -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>
|
||||
|
@ -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");
|
||||
|
||||
|
@ -22,6 +22,8 @@ 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;
|
||||
@ -33,13 +35,16 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* @author Jan-Willem Veldhuis - Initial contribution
|
||||
* 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
|
||||
public class DenonMarantzDiscoveryParticipant implements MDNSDiscoveryParticipant {
|
||||
@Component(configurationPid = "discovery.denonmarantz")
|
||||
@NonNullByDefault
|
||||
public class DenonMarantzMDNSDiscoveryParticipant implements MDNSDiscoveryParticipant {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(DenonMarantzDiscoveryParticipant.class);
|
||||
private Logger logger = LoggerFactory.getLogger(DenonMarantzMDNSDiscoveryParticipant.class);
|
||||
|
||||
// Service type for 'Airplay enabled' receivers
|
||||
private static final String RAOP_SERVICE_TYPE = "_raop._tcp.local.";
|
||||
@ -47,21 +52,15 @@ public class DenonMarantzDiscoveryParticipant implements MDNSDiscoveryParticipan
|
||||
/**
|
||||
* 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
|
||||
* 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\\.$");
|
||||
|
||||
/**
|
||||
* 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";
|
||||
private static final String DENON_MODEL_PREFIX = "denon";
|
||||
private static final String MARANTZ_MODEL_PREFIX = "marantz";
|
||||
|
||||
@Override
|
||||
public Set<ThingTypeUID> getSupportedThingTypeUIDs() {
|
||||
@ -74,55 +73,58 @@ public class DenonMarantzDiscoveryParticipant implements MDNSDiscoveryParticipan
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
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 {
|
||||
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()) {
|
@ -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());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user