]> git.basschouten.com Git - openhab-addons.git/blob
e62431b21f465d9fbdf7060cbc377b592bd4dfed
[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.openwebnet.internal.discovery;
14
15 import java.util.Arrays;
16 import java.util.Collections;
17 import java.util.HashMap;
18 import java.util.Map;
19 import java.util.Optional;
20 import java.util.Set;
21
22 import org.eclipse.jdt.annotation.NonNullByDefault;
23 import org.eclipse.jdt.annotation.Nullable;
24 import org.jupnp.model.meta.DeviceDetails;
25 import org.jupnp.model.meta.ManufacturerDetails;
26 import org.jupnp.model.meta.ModelDetails;
27 import org.jupnp.model.meta.RemoteDevice;
28 import org.jupnp.model.meta.RemoteDeviceIdentity;
29 import org.jupnp.model.types.UDN;
30 import org.openhab.binding.openwebnet.internal.OpenWebNetBindingConstants;
31 import org.openhab.core.config.discovery.DiscoveryResult;
32 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
33 import org.openhab.core.config.discovery.upnp.UpnpDiscoveryParticipant;
34 import org.openhab.core.thing.ThingTypeUID;
35 import org.openhab.core.thing.ThingUID;
36 import org.osgi.service.component.annotations.Component;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 /**
41  * The {@link BusGatewayUpnpDiscovery} is responsible for discovering supported BTicino BUS
42  * gateways devices using UPnP. It implements {@link UpnpDiscoveryParticipant}.
43  *
44  * @author Massimo Valla - Initial contribution
45  */
46 @NonNullByDefault
47 @Component(service = UpnpDiscoveryParticipant.class)
48 public class BusGatewayUpnpDiscovery implements UpnpDiscoveryParticipant {
49
50     private final Logger logger = LoggerFactory.getLogger(BusGatewayUpnpDiscovery.class);
51
52     public enum BusGatewayId {
53         MH201("IPscenarioModule", "MH201"),
54         MH202("scheduler", "MH202"),
55         F454("webserver", "F454"),
56         MY_HOME_SERVER1("myhomeserver1", "MYHOMESERVER1"),
57         TOUCH_SCREEN_3_5("touchscreen", "TOUCHSCREEN3_5"),
58         TOUCH_SCREEN_10("ts10", "TOUCHSCREEN10"),
59         MH200N("lightingcontrolunit", "MH200N");
60
61         private final String discoveryString, thingId;
62
63         private BusGatewayId(String value, String thingId) {
64             this.discoveryString = value;
65             this.thingId = thingId;
66         }
67
68         public static @Nullable BusGatewayId fromValue(String s) {
69             Optional<BusGatewayId> m = Arrays.stream(values()).filter(val -> s.equals(val.discoveryString)).findFirst();
70             if (m.isPresent()) {
71                 return m.get();
72             } else {
73                 return null;
74             }
75         }
76
77         public String getThingId() {
78             return thingId;
79         }
80     }
81
82     /**
83      * DeviceInfo bean to store device useful info (and log them)
84      */
85     public class DeviceInfo {
86         @Nullable
87         private String friendlyName;
88         private String modelName = "<unknown>";
89         private String modelDescription = "<unknown>";
90         private String modelNumber = "<unknown>";
91         private String serialNumber = "<unknown>";
92         @Nullable
93         private String host;
94         private String manufacturer = "<unknown>";
95         @Nullable
96         private UDN udn;
97         private boolean isBTicino = false;
98
99         private DeviceInfo(RemoteDevice device) {
100             String deviceLog = "Discovered device:\n+=== UPnP =========================================";
101             RemoteDeviceIdentity identity = device.getIdentity();
102             if (identity != null) {
103                 this.udn = identity.getUdn();
104                 deviceLog += "\n| ID.UDN       : " + udn;
105                 if (identity.getDescriptorURL() != null) {
106                     deviceLog += "\n| ID.DESC URL  : " + identity.getDescriptorURL();
107                     this.host = identity.getDescriptorURL().getHost();
108                 }
109                 deviceLog += "\n| ID.MAX AGE : " + identity.getMaxAgeSeconds();
110             }
111             deviceLog += "\n| --------------";
112             DeviceDetails details = device.getDetails();
113             if (details != null) {
114                 ManufacturerDetails manufacturerDetails = details.getManufacturerDetails();
115                 if (manufacturerDetails != null) {
116                     this.manufacturer = manufacturerDetails.getManufacturer();
117                     deviceLog += "\n| MANUFACTURER : " + manufacturer + " (" + manufacturerDetails.getManufacturerURI()
118                             + ")";
119                     if (manufacturer.toUpperCase().contains("BTICINO")) {
120                         this.isBTicino = true;
121                     }
122                 }
123                 ModelDetails modelDetails = details.getModelDetails();
124                 if (modelDetails != null) {
125                     // Model Name | Desc | Number (Uri)
126                     this.modelName = modelDetails.getModelName();
127                     this.modelDescription = modelDetails.getModelDescription();
128                     this.modelNumber = modelDetails.getModelNumber();
129                     deviceLog += "\n| MODEL        : " + modelName + " | " + modelDescription + " | " + modelNumber
130                             + " (" + modelDetails.getModelURI() + ")";
131                 }
132                 if (isBTicino) {
133                     this.friendlyName = details.getFriendlyName();
134                     deviceLog += "\n| FRIENDLY NAME: " + friendlyName;
135                     this.serialNumber = details.getSerialNumber();
136                     deviceLog += "\n| SERIAL #     : " + serialNumber;
137                     deviceLog += "\n| BASE URL     : " + details.getBaseURL();
138                     deviceLog += "\n| UPC          : " + details.getUpc();
139                 }
140             }
141             deviceLog += "\n+==================================================";
142             logger.debug(deviceLog);
143         }
144     } /* DeviceInfo */
145
146     @Override
147     public Set<ThingTypeUID> getSupportedThingTypeUIDs() {
148         return Collections.singleton(OpenWebNetBindingConstants.THING_TYPE_BUS_GATEWAY);
149     }
150
151     @Override
152     public @Nullable DiscoveryResult createResult(RemoteDevice device) {
153         logger.debug("Found device {}", device.getType());
154         DeviceInfo devInfo = new DeviceInfo(device);
155         if (!devInfo.manufacturer.matches("<unknown>")) {
156             logger.debug("                              |- {} ({})", devInfo.modelName, devInfo.manufacturer);
157         }
158         ThingUID thingId = generateThingUID(devInfo);
159         if (thingId != null) {
160             String host = devInfo.host;
161             if (host != null) {
162                 String label = "BUS Gateway";
163                 String fn = devInfo.friendlyName;
164                 if (fn != null) {
165                     if (!fn.isEmpty()) {
166                         label = fn;
167                     }
168                 }
169                 label = label + " (" + devInfo.modelName + ", " + devInfo.modelNumber + ", " + devInfo.host + ")";
170                 Map<String, Object> properties = new HashMap<>(4);
171                 properties.put(OpenWebNetBindingConstants.CONFIG_PROPERTY_HOST, host);
172                 properties.put(OpenWebNetBindingConstants.PROPERTY_FIRMWARE_VERSION, devInfo.modelNumber);
173                 properties.put(OpenWebNetBindingConstants.PROPERTY_MODEL, devInfo.modelName);
174                 properties.put(OpenWebNetBindingConstants.PROPERTY_SERIAL_NO, devInfo.serialNumber);
175                 DiscoveryResult result = DiscoveryResultBuilder.create(thingId).withProperties(properties)
176                         .withRepresentationProperty(OpenWebNetBindingConstants.PROPERTY_SERIAL_NO).withLabel(label)
177                         .build();
178                 UDN udn = devInfo.udn;
179                 String udnStr;
180                 if (udn != null) {
181                     udnStr = udn.getIdentifierString();
182                 } else {
183                     udnStr = null;
184                 }
185                 logger.info("Created a DiscoveryResult for gateway '{}' (UDN={})", devInfo.friendlyName, udnStr);
186                 return result;
187             } else {
188                 logger.warn("Could not get host for device (UDN={})", devInfo.udn);
189                 return null;
190             }
191         } else {
192             return null;
193         }
194     }
195
196     @Override
197     public @Nullable ThingUID getThingUID(RemoteDevice device) {
198         return generateThingUID(new DeviceInfo(device));
199     }
200
201     /**
202      * Returns a ThingUID for supported devices from already extracted DeviceInfo
203      *
204      * @param devInfo the device info
205      * @return a new ThingUID, or null if the device is not supported by the binding
206      */
207     private @Nullable ThingUID generateThingUID(DeviceInfo devInfo) {
208         if (devInfo.isBTicino) {
209             UDN udn = devInfo.udn;
210             String idString = null;
211             if (udn != null) {
212                 idString = udn.getIdentifierString();
213                 if (idString != null) {
214                     String[] spl = idString.split("-");
215                     if (spl.length > 3) {
216                         BusGatewayId gwId = BusGatewayId.fromValue(spl[1]);
217                         if (gwId != null) {
218                             logger.debug("'{}' is a supported gateway", gwId);
219                             String mac = spl[3]; // extract MAC address
220                             String normalizedMac = mac.toLowerCase().replaceAll("[^a-f0-9]", "");
221                             if (!normalizedMac.isEmpty()) {
222                                 return new ThingUID(OpenWebNetBindingConstants.THING_TYPE_BUS_GATEWAY,
223                                         gwId.getThingId() + "_" + normalizedMac);
224                             }
225                         }
226                     }
227                 }
228             }
229             logger.info("Found BTicino device: not an OpenWebNet gateway or not supported (UDN={})", idString);
230         }
231         return null;
232     }
233 }