]> git.basschouten.com Git - openhab-addons.git/blob
b73d8e9c93335d6201f062786d2a8587ddbb9169
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 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.fsinternetradio.internal;
14
15 import static org.openhab.binding.fsinternetradio.internal.FSInternetRadioBindingConstants.*;
16
17 import java.util.Collections;
18 import java.util.HashMap;
19 import java.util.HashSet;
20 import java.util.Map;
21 import java.util.Set;
22
23 import org.jupnp.model.meta.DeviceDetails;
24 import org.jupnp.model.meta.ManufacturerDetails;
25 import org.jupnp.model.meta.ModelDetails;
26 import org.jupnp.model.meta.RemoteDevice;
27 import org.jupnp.model.meta.RemoteDeviceIdentity;
28 import org.openhab.core.config.discovery.DiscoveryResult;
29 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
30 import org.openhab.core.config.discovery.upnp.UpnpDiscoveryParticipant;
31 import org.openhab.core.thing.ThingTypeUID;
32 import org.openhab.core.thing.ThingUID;
33 import org.osgi.service.component.annotations.Component;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 /**
38  * This is the discovery service for internet radios based on the fontier silicon chipset. Unfortunately, it is not
39  * easily possible to detect from the upnp information which devices are supported. So currently, discovery only works
40  * for medion internet radios. {@link FSInternetRadioDiscoveryParticipant#getThingUID(RemoteDevice)} must be extended to
41  * add further supported devices!
42  *
43  * @author Patrick Koenemann - Initial contribution
44  * @author Mihaela Memova - removed the getLabel(RemoteDevice device) method due to its unreachable code lines
45  * @author Markus Michels - support for Teufel 3sixty discovery
46  */
47 @Component
48 public class FSInternetRadioDiscoveryParticipant implements UpnpDiscoveryParticipant {
49     private final Logger logger = LoggerFactory.getLogger(FSInternetRadioDiscoveryParticipant.class);
50
51     /** Map from UPnP manufacturer to model number for supported radios; filled in static initializer below. */
52     private static final Map<String, Set<String>> SUPPORTED_RADIO_MODELS = new HashMap<>();
53
54     static {
55         // to allow case-insensitive match: add all values UPPER-CASE!
56
57         // format: MANUFACTURER -> MODEL NAME, as shown e.g. by UPnP Tester as explained here:
58         // https://community.openhab.org/t/internet-radio-i-need-your-help/2131
59
60         // list of medion internet radios taken from: http://internetradio.medion.com/
61         final Set<String> medionRadios = new HashSet<>();
62         SUPPORTED_RADIO_MODELS.put("MEDION AG", medionRadios);
63         medionRadios.add("MD83813");
64         medionRadios.add("MD84017");
65         medionRadios.add("MD85651");
66         medionRadios.add("MD86062");
67         medionRadios.add("MD86250");
68         medionRadios.add("MD86562");
69         medionRadios.add("MD86672");
70         medionRadios.add("MD86698");
71         medionRadios.add("MD86869");
72         medionRadios.add("MD86891");
73         medionRadios.add("MD86955");
74         medionRadios.add("MD86988");
75         medionRadios.add("MD87090");
76         medionRadios.add("MD87180");
77         medionRadios.add("MD87238");
78         medionRadios.add("MD87267");
79
80         // list of hama internet radios taken from:
81         // https://www.hama.com/action/searchCtrl/search?searchMode=1&q=Internet%20Radio
82         final Set<String> hamaRadios = new HashSet<>();
83         SUPPORTED_RADIO_MODELS.put("HAMA", hamaRadios);
84         hamaRadios.add("IR100");
85         hamaRadios.add("IR110");
86         hamaRadios.add("IR250");
87         hamaRadios.add("IR320");
88         hamaRadios.add("DIR3000");
89         hamaRadios.add("DIR3100");
90         hamaRadios.add("DIR3110");
91
92         // as reported in: https://community.openhab.org/t/internet-radio-i-need-your-help/2131/19
93         // and: https://community.openhab.org/t/internet-radio-i-need-your-help/2131/20
94         // and: https://community.openhab.org/t/internet-radio-i-need-your-help/2131/23
95         // these radios do not provide model number, but the model name should also be ok
96         final Set<String> radiosWithoutManufacturer = new HashSet<>();
97         radiosWithoutManufacturer.add(""); // empty manufacturer / model name
98         radiosWithoutManufacturer.add(null); // missing manufacturer / model name
99         SUPPORTED_RADIO_MODELS.put("SMRS18A1", radiosWithoutManufacturer);
100         SUPPORTED_RADIO_MODELS.put("SMRS30A1", radiosWithoutManufacturer);
101         SUPPORTED_RADIO_MODELS.put("SMRS35A1", radiosWithoutManufacturer);
102
103         final Set<String> teufelRadios = new HashSet<>();
104         SUPPORTED_RADIO_MODELS.put("Teufel", teufelRadios);
105         teufelRadios.add("Radio 3sixty");
106
107         // as reported in: https://community.openhab.org/t/internet-radio-i-need-your-help/2131/5
108         final Set<String> ttmicroRadios = new HashSet<>();
109         SUPPORTED_RADIO_MODELS.put("TTMICRO AS", ttmicroRadios);
110         ttmicroRadios.add("PINELL SUPERSOUND");
111
112         // as reported in: https://community.openhab.org/t/internet-radio-i-need-your-help/2131/7
113         final Set<String> revoRadios = new HashSet<>();
114         SUPPORTED_RADIO_MODELS.put("REVO TECHNOLOGIES LTD", revoRadios);
115         revoRadios.add("S10");
116
117         // as reported in: https://community.openhab.org/t/internet-radio-i-need-your-help/2131/10
118         // and: https://community.openhab.org/t/internet-radio-i-need-your-help/2131/21
119         final Set<String> robertsRadios = new HashSet<>();
120         SUPPORTED_RADIO_MODELS.put("ROBERTS RADIO LIMITED", robertsRadios);
121         robertsRadios.add("ROBERTS STREAM 93I");
122         robertsRadios.add("ROBERTS STREAM 83I");
123
124         // as reported in: https://community.openhab.org/t/internet-radio-i-need-your-help/2131/11
125         final Set<String> aunaRadios = new HashSet<>();
126         SUPPORTED_RADIO_MODELS.put("AUNA", aunaRadios);
127         aunaRadios.add("10028154 & 10028155");
128         aunaRadios.add("10028154");
129         aunaRadios.add("10028155");
130
131         // as reported in: https://community.openhab.org/t/internet-radio-i-need-your-help/2131/22
132         final Set<String> sangeanRadios = new HashSet<>();
133         SUPPORTED_RADIO_MODELS.put("SANGEAN RADIO LIMITED", sangeanRadios);
134         sangeanRadios.add("28");
135
136         // as reported in: https://community.openhab.org/t/internet-radio-i-need-your-help/2131/25
137         final Set<String> rokuRadios = new HashSet<>();
138         SUPPORTED_RADIO_MODELS.put("ROKU", rokuRadios);
139         rokuRadios.add("M1001");
140     }
141
142     @Override
143     public Set<ThingTypeUID> getSupportedThingTypeUIDs() {
144         return Collections.singleton(THING_TYPE_RADIO);
145     }
146
147     @Override
148     public DiscoveryResult createResult(RemoteDevice device) {
149         final ThingUID uid = getThingUID(device);
150         if (uid != null) {
151             final Map<String, Object> properties = new HashMap<>(1);
152             final String ip = getIp(device);
153             if (ip != null) {
154                 properties.put(CONFIG_PROPERTY_IP, ip);
155
156                 // add manufacturer and model, if provided
157                 final String manufacturer = getManufacturer(device);
158                 if (manufacturer != null) {
159                     properties.put(PROPERTY_MANUFACTURER, manufacturer);
160                 }
161                 final String dm = getModel(device);
162                 final String model = dm != null ? dm : getFriendlyName(device);
163                 if (model != null) {
164                     properties.put(PROPERTY_MODEL, model);
165                 }
166                 final String thingName = (manufacturer == null) && (getModel(device) == null) ? getFriendlyName(device)
167                         : device.getDisplayString();
168                 return DiscoveryResultBuilder.create(uid).withProperties(properties).withLabel(thingName).build();
169             }
170         }
171         return null;
172     }
173
174     private String getManufacturer(RemoteDevice device) {
175         final DeviceDetails details = device.getDetails();
176         if ((details != null) && (details.getManufacturerDetails() != null)) {
177             String manufacturer = details.getManufacturerDetails().getManufacturer().trim();
178             return manufacturer.isEmpty() ? null : manufacturer;
179         }
180         return null;
181     }
182
183     private String getModel(RemoteDevice device) {
184         final DeviceDetails details = device.getDetails();
185         if ((details != null) && (details.getModelDetails().getModelNumber() != null)) {
186             String model = details.getModelDetails().getModelNumber().trim();
187             return model.isEmpty() ? null : model;
188         }
189         return null;
190     }
191
192     private String getFriendlyName(RemoteDevice device) {
193         final DeviceDetails details = device.getDetails();
194         if ((details != null) && (details.getFriendlyName() != null)) {
195             String name = details.getFriendlyName().trim();
196             return name.isEmpty() ? null : name;
197         }
198         return null;
199     }
200
201     private String getIp(RemoteDevice device) {
202         final DeviceDetails details = device.getDetails();
203         if (details != null) {
204             if (details.getBaseURL() != null) {
205                 return details.getBaseURL().getHost();
206             }
207         }
208         final RemoteDeviceIdentity identity = device.getIdentity();
209         if (identity != null) {
210             if (identity.getDescriptorURL() != null) {
211                 return identity.getDescriptorURL().getHost();
212             }
213         }
214         return null;
215     }
216
217     /**
218      * If <code>device</code> is a supported device, a unique thing ID (e.g. serial number) must be returned. Further
219      * supported devices should be added here, based on the available UPnP information.
220      */
221     @SuppressWarnings("null")
222     @Override
223     public ThingUID getThingUID(RemoteDevice device) {
224         final DeviceDetails details = device.getDetails();
225         final String friendlyName = details.getFriendlyName();
226         logger.debug("Discovered unit:  {}", friendlyName);
227
228         if (details != null) {
229             final ManufacturerDetails manufacturerDetails = details.getManufacturerDetails();
230             final ModelDetails modelDetails = details.getModelDetails();
231             if (modelDetails != null) {
232                 // check manufacturer and model number
233                 final String manufacturer = manufacturerDetails == null ? null : manufacturerDetails.getManufacturer();
234                 final String modelNumber = modelDetails.getModelNumber();
235                 String serialNumber = details.getSerialNumber();
236                 logger.debug("Discovered unit: {} {} - {}", manufacturer, modelNumber, friendlyName);
237                 if (modelNumber != null) {
238                     if (manufacturer != null) {
239                         final Set<String> supportedRadios = SUPPORTED_RADIO_MODELS
240                                 .get(manufacturer.trim().toUpperCase());
241                         if (supportedRadios != null && supportedRadios.contains(modelNumber.toUpperCase())) {
242                             return new ThingUID(THING_TYPE_RADIO, serialNumber);
243                         }
244                     }
245                     // check model name and number
246                     final String modelName = modelDetails.getModelName();
247                     if (modelName != null) {
248                         final Set<String> supportedRadios = SUPPORTED_RADIO_MODELS.get(modelName.trim().toUpperCase());
249                         if (supportedRadios != null && supportedRadios.contains(modelNumber.toUpperCase())) {
250                             return new ThingUID(THING_TYPE_RADIO, serialNumber);
251                         }
252                         // Teufel reports empty manufacturer and model, but friendly name
253                         if (friendlyName.contains("Teufel")) {
254                             logger.debug("haha");
255                         }
256                         if (!friendlyName.isEmpty()) {
257                             for (Set<String> models : SUPPORTED_RADIO_MODELS.values()) {
258                                 for (String model : models) {
259                                     if ((model != null) && !model.isEmpty() && friendlyName.contains(model)) {
260                                         return new ThingUID(THING_TYPE_RADIO, serialNumber);
261                                     }
262                                 }
263                             }
264                         }
265                     }
266                 }
267
268                 if (((manufacturer == null) || manufacturer.trim().isEmpty())
269                         && ((modelNumber == null) || modelNumber.trim().isEmpty())) {
270                     // Some devices report crappy UPnP device description so manufacturer and model are ""
271                     // In this case we try to find the match in friendlyName
272                     final String uname = friendlyName.toUpperCase();
273                     for (Set<String> set : SUPPORTED_RADIO_MODELS.values()) {
274                         for (String model : set) {
275                             if ((model != null) && !model.isEmpty() && uname.contains(model)) {
276                                 return new ThingUID(THING_TYPE_RADIO, serialNumber);
277                             }
278                         }
279                     }
280                 }
281             }
282             // maybe we can add further indicators, whether the device is a supported one
283         }
284         // device not supported
285         return null;
286     }
287 }