]> git.basschouten.com Git - openhab-addons.git/blob
2bbfc16282e6d3c634d8eb34940d75b0db1d6648
[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.shelly.internal.discovery;
14
15 import static org.openhab.binding.shelly.internal.ShellyBindingConstants.*;
16 import static org.openhab.binding.shelly.internal.util.ShellyUtils.*;
17
18 import java.io.IOException;
19 import java.net.Inet4Address;
20 import java.util.Set;
21
22 import javax.jmdns.ServiceInfo;
23
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.eclipse.jdt.annotation.Nullable;
26 import org.eclipse.jetty.client.HttpClient;
27 import org.openhab.binding.shelly.internal.config.ShellyBindingConfiguration;
28 import org.openhab.binding.shelly.internal.config.ShellyThingConfiguration;
29 import org.openhab.binding.shelly.internal.provider.ShellyTranslationProvider;
30 import org.openhab.core.config.discovery.DiscoveryResult;
31 import org.openhab.core.config.discovery.mdns.MDNSDiscoveryParticipant;
32 import org.openhab.core.i18n.LocaleProvider;
33 import org.openhab.core.io.net.http.HttpClientFactory;
34 import org.openhab.core.thing.ThingTypeUID;
35 import org.openhab.core.thing.ThingUID;
36 import org.osgi.service.cm.Configuration;
37 import org.osgi.service.cm.ConfigurationAdmin;
38 import org.osgi.service.component.ComponentContext;
39 import org.osgi.service.component.annotations.Activate;
40 import org.osgi.service.component.annotations.Component;
41 import org.osgi.service.component.annotations.Modified;
42 import org.osgi.service.component.annotations.Reference;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45
46 /**
47  * This class identifies Shelly devices by their mDNS service information.
48  *
49  * @author Markus Michels - Initial contribution
50  */
51 @NonNullByDefault
52 @Component(service = MDNSDiscoveryParticipant.class)
53 public class ShellyDiscoveryParticipant implements MDNSDiscoveryParticipant {
54     private final Logger logger = LoggerFactory.getLogger(ShellyDiscoveryParticipant.class);
55     private final ShellyBindingConfiguration bindingConfig = new ShellyBindingConfiguration();
56     private final ShellyTranslationProvider messages;
57     private final HttpClient httpClient;
58     private final ConfigurationAdmin configurationAdmin;
59
60     @Activate
61     public ShellyDiscoveryParticipant(@Reference ConfigurationAdmin configurationAdmin,
62             @Reference HttpClientFactory httpClientFactory, @Reference LocaleProvider localeProvider,
63             @Reference ShellyTranslationProvider translationProvider, ComponentContext componentContext) {
64         logger.debug("Activating ShellyDiscovery service");
65         this.configurationAdmin = configurationAdmin;
66         this.messages = translationProvider;
67         this.httpClient = httpClientFactory.getCommonHttpClient();
68         bindingConfig.updateFromProperties(componentContext.getProperties());
69     }
70
71     @Override
72     public Set<ThingTypeUID> getSupportedThingTypeUIDs() {
73         return SUPPORTED_THING_TYPES_UIDS;
74     }
75
76     @Override
77     public String getServiceType() {
78         return SERVICE_TYPE;
79     }
80
81     /**
82      * Process updates to Binding Config
83      *
84      * @param componentContext
85      */
86     @Modified
87     protected void modified(final ComponentContext componentContext) {
88         logger.debug("Shelly Binding Configuration refreshed");
89         bindingConfig.updateFromProperties(componentContext.getProperties());
90     }
91
92     @Nullable
93     @Override
94     public DiscoveryResult createResult(final ServiceInfo service) {
95         String name = service.getName().toLowerCase(); // Shelly Duo: Name starts with" Shelly" rather than "shelly"
96         if (!name.startsWith("shelly")) {
97             return null;
98         }
99
100         try {
101             String address = "";
102             name = service.getName().toLowerCase();
103             Inet4Address[] hostAddresses = service.getInet4Addresses();
104             if ((hostAddresses != null) && (hostAddresses.length > 0)) {
105                 address = substringAfter(hostAddresses[0].toString(), "/");
106             }
107             if (address.isEmpty()) {
108                 logger.trace("{}: Shelly device discovered with empty IP address (service-name={})", name, service);
109                 return null;
110             }
111             String thingType = service.getQualifiedName().contains(SERVICE_TYPE) && name.contains("-")
112                     ? substringBeforeLast(name, "-")
113                     : name;
114             logger.debug("{}: Shelly device discovered: IP-Adress={}, type={}", name, address, thingType);
115
116             // Get device settings
117             Configuration serviceConfig = configurationAdmin.getConfiguration("binding.shelly");
118             if (serviceConfig.getProperties() != null) {
119                 bindingConfig.updateFromProperties(serviceConfig.getProperties());
120             }
121
122             ShellyThingConfiguration config = new ShellyThingConfiguration();
123             config.deviceIp = address;
124             config.userId = bindingConfig.defaultUserId;
125             config.password = bindingConfig.defaultPassword;
126
127             String gen = getString(service.getPropertyString("gen"));
128             boolean gen2 = "2".equals(gen) || "3".equals(gen);
129             return ShellyBasicDiscoveryService.createResult(gen2, name, address, bindingConfig, httpClient, messages);
130         } catch (IOException | NullPointerException e) {
131             // maybe some format description was buggy
132             logger.debug("{}: Exception on processing serviceInfo '{}'", name, service.getNiceTextString(), e);
133         }
134         return null;
135     }
136
137     @Nullable
138     @Override
139     public ThingUID getThingUID(@Nullable ServiceInfo service) throws IllegalArgumentException {
140         logger.debug("ServiceInfo {}", service);
141         if (service == null) {
142             throw new IllegalArgumentException("service must not be null!");
143         }
144         String serviceName = service.getName();
145         if (serviceName == null) {
146             throw new IllegalArgumentException("serviceName must not be null!");
147         }
148         serviceName = serviceName.toLowerCase();
149         if (!serviceName.contains(VENDOR.toLowerCase())) {
150             logger.debug("Not a " + VENDOR + " device!");
151             return null;
152         }
153         return ShellyThingCreator.getThingUID(serviceName, "", "", false);
154     }
155 }