]> git.basschouten.com Git - openhab-addons.git/blob
11046098d14c865c6643900dafdd5498afd5683d
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2024 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.denonmarantz.internal.discovery;
14
15 import static org.openhab.binding.denonmarantz.internal.DenonMarantzBindingConstants.*;
16
17 import java.util.HashMap;
18 import java.util.Map;
19 import java.util.Set;
20 import java.util.regex.Matcher;
21 import java.util.regex.Pattern;
22
23 import javax.jmdns.ServiceInfo;
24
25 import org.openhab.core.config.discovery.DiscoveryResult;
26 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
27 import org.openhab.core.config.discovery.mdns.MDNSDiscoveryParticipant;
28 import org.openhab.core.thing.Thing;
29 import org.openhab.core.thing.ThingTypeUID;
30 import org.openhab.core.thing.ThingUID;
31 import org.osgi.service.component.annotations.Component;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 /**
36  * @author Jan-Willem Veldhuis - Initial contribution
37  *
38  */
39 @Component
40 public class DenonMarantzDiscoveryParticipant implements MDNSDiscoveryParticipant {
41
42     private Logger logger = LoggerFactory.getLogger(DenonMarantzDiscoveryParticipant.class);
43
44     // Service type for 'Airplay enabled' receivers
45     private static final String RAOP_SERVICE_TYPE = "_raop._tcp.local.";
46
47     /**
48      * Match the serial number, vendor and model of the discovered AVR.
49      * Input is like "0006781D58B1@Marantz SR5008._raop._tcp.local."
50      * A Denon AVR serial (MAC address) starts with 0005CD
51      * A Marantz AVR serial (MAC address) starts with 000678
52      */
53     private static final Pattern DENON_MARANTZ_PATTERN = Pattern
54             .compile("^((?:0005CD|000678)[A-Z0-9]+)@(.+)\\._raop\\._tcp\\.local\\.$");
55
56     /**
57      * Denon AVRs have a MAC address / serial number starting with 0005CD
58      */
59     private static final String DENON_MAC_PREFIX = "0005CD";
60
61     /**
62      * Marantz AVRs have a MAC address / serial number starting with 000678
63      */
64     private static final String MARANTZ_MAC_PREFIX = "000678";
65
66     @Override
67     public Set<ThingTypeUID> getSupportedThingTypeUIDs() {
68         return Set.of(THING_TYPE_AVR);
69     }
70
71     @Override
72     public String getServiceType() {
73         return RAOP_SERVICE_TYPE;
74     }
75
76     @Override
77     public DiscoveryResult createResult(ServiceInfo serviceInfo) {
78         String qualifiedName = serviceInfo.getQualifiedName();
79         logger.debug("AVR found: {}", qualifiedName);
80         ThingUID thingUID = getThingUID(serviceInfo);
81         if (thingUID != null) {
82             Matcher matcher = DENON_MARANTZ_PATTERN.matcher(qualifiedName);
83             matcher.matches(); // we already know it matches, it was matched in getThingUID
84             String serial = matcher.group(1).toLowerCase();
85
86             /**
87              * The Vendor is not available from the mDNS result.
88              * We assign the Vendor based on our assumptions of the MAC address prefix.
89              */
90             String vendor = "";
91             if (serial.startsWith(MARANTZ_MAC_PREFIX)) {
92                 vendor = "Marantz";
93             } else if (serial.startsWith(DENON_MAC_PREFIX)) {
94                 vendor = "Denon";
95             }
96
97             // 'am=...' property describes the model name
98             String model = serviceInfo.getPropertyString("am");
99             String friendlyName = matcher.group(2).trim();
100
101             Map<String, Object> properties = new HashMap<>(2);
102
103             if (serviceInfo.getHostAddresses().length == 0) {
104                 logger.debug("Could not determine IP address for the Denon/Marantz AVR");
105                 return null;
106             }
107             String host = serviceInfo.getHostAddresses()[0];
108
109             logger.debug("IP Address: {}", host);
110
111             properties.put(PARAMETER_HOST, host);
112             properties.put(Thing.PROPERTY_SERIAL_NUMBER, serial);
113             properties.put(Thing.PROPERTY_VENDOR, vendor);
114             properties.put(Thing.PROPERTY_MODEL_ID, model);
115
116             String label = friendlyName + " (" + vendor + ' ' + model + ")";
117             return DiscoveryResultBuilder.create(thingUID).withProperties(properties).withLabel(label)
118                     .withRepresentationProperty(Thing.PROPERTY_SERIAL_NUMBER).build();
119
120         } else {
121             return null;
122         }
123     }
124
125     @Override
126     public ThingUID getThingUID(ServiceInfo service) {
127         Matcher matcher = DENON_MARANTZ_PATTERN.matcher(service.getQualifiedName());
128         if (matcher.matches()) {
129             logger.debug("This seems like a supported Denon/Marantz AVR!");
130             String serial = matcher.group(1).toLowerCase();
131             return new ThingUID(THING_TYPE_AVR, serial);
132         } else {
133             logger.trace("This discovered device is not supported by the DenonMarantz binding, ignoring..");
134         }
135         return null;
136     }
137 }