]> git.basschouten.com Git - openhab-addons.git/blob
13091d770267a802e0f678466f9760a09683a650
[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.liquidcheck.internal.discovery;
14
15 import static org.openhab.binding.liquidcheck.internal.LiquidCheckBindingConstants.SUPPORTED_THING_TYPES_UIDS;
16 import static org.openhab.binding.liquidcheck.internal.LiquidCheckBindingConstants.THING_TYPE_LIQUID_CHECK;
17
18 import java.io.IOException;
19 import java.net.Inet4Address;
20 import java.net.InetAddress;
21 import java.net.NetworkInterface;
22 import java.net.SocketException;
23 import java.net.UnknownHostException;
24 import java.util.ArrayList;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.concurrent.ExecutionException;
28 import java.util.concurrent.TimeoutException;
29
30 import org.eclipse.jdt.annotation.NonNullByDefault;
31 import org.eclipse.jetty.client.HttpClient;
32 import org.eclipse.jetty.client.api.ContentResponse;
33 import org.eclipse.jetty.client.api.Request;
34 import org.eclipse.jetty.http.HttpMethod;
35 import org.openhab.binding.liquidcheck.internal.json.CommData;
36 import org.openhab.core.config.discovery.AbstractDiscoveryService;
37 import org.openhab.core.config.discovery.DiscoveryResult;
38 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
39 import org.openhab.core.config.discovery.DiscoveryService;
40 import org.openhab.core.io.net.http.HttpClientFactory;
41 import org.openhab.core.thing.ThingUID;
42 import org.osgi.service.component.annotations.Activate;
43 import org.osgi.service.component.annotations.Component;
44 import org.osgi.service.component.annotations.Reference;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47
48 import com.google.gson.Gson;
49 import com.google.gson.JsonSyntaxException;
50
51 /**
52  * The {@link LiquidCheckDiscoveryService} class defines discovery service for the LiquidCheckBinding
53  *
54  * @author Marcel Goerentz - Initial contribution
55  */
56 @NonNullByDefault
57 @Component(service = DiscoveryService.class, immediate = true, configurationPid = "discovery.liquidcheck")
58 public class LiquidCheckDiscoveryService extends AbstractDiscoveryService {
59
60     private static final int DISCOVER_TIMEOUT_SECONDS = 300;
61
62     private final Logger logger = LoggerFactory.getLogger(this.getClass());
63     private final HttpClient httpClient;
64
65     @Activate
66     public LiquidCheckDiscoveryService(@Reference HttpClientFactory httpClientFactory) {
67         super(SUPPORTED_THING_TYPES_UIDS, DISCOVER_TIMEOUT_SECONDS, false);
68         httpClient = httpClientFactory.getCommonHttpClient();
69     }
70
71     /**
72      * Method for starting the scan
73      */
74     @Override
75     protected void startScan() {
76         scheduler.execute(liquidCheckDiscoveryRunnable());
77     }
78
79     /**
80      * Method to stop the scan
81      */
82     @Override
83     protected synchronized void stopScan() {
84         super.stopScan();
85         removeOlderResults(getTimestampOfLastScan());
86     }
87
88     /**
89      * Method for creating a Runnable to start a scan
90      * 
91      * @return the Runnable
92      */
93     protected Runnable liquidCheckDiscoveryRunnable() {
94         return () -> {
95             try {
96                 List<InetAddress> addresses = getIPv4Addresses();
97                 List<InetAddress> hosts = findActiveHosts(addresses);
98                 for (InetAddress host : hosts) {
99                     Request request = httpClient.newRequest("http://" + host.getHostAddress() + "/infos.json")
100                             .method(HttpMethod.GET).followRedirects(false);
101                     try {
102                         ContentResponse response = request.send();
103                         if (response.getStatus() == 200) {
104                             CommData json = null;
105                             try {
106                                 json = new Gson().fromJson(response.getContentAsString(), CommData.class);
107                             } catch (JsonSyntaxException e) {
108                                 logger.debug("Json Syntax Exception!");
109                             }
110                             if (null != json) {
111                                 buildDiscoveryResult(json,
112                                         InetAddress.getByName(json.payload.wifi.station.hostname).isReachable(50));
113                             } else {
114                                 logger.debug("Response Object is null!");
115                             }
116                         }
117                     } catch (TimeoutException e) {
118                         logger.debug("TimeOut: {}", e.getMessage());
119                     } catch (ExecutionException e) {
120                         logger.debug("ExecutionException: {}", e.getMessage());
121                     } catch (InterruptedException e) {
122                         Thread.currentThread().interrupt();
123                     }
124
125                 }
126             } catch (IOException e) {
127                 logger.debug("Message: {}", e.getMessage());
128             }
129         };
130     }
131
132     /**
133      * This Method retrieves all IPv4 addresses of the server
134      * 
135      * @return A list of all available IPv4 addresses that are registered
136      * @throws SocketException
137      */
138     private List<InetAddress> getIPv4Addresses() throws SocketException {
139         Iterator<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces().asIterator();
140         List<InetAddress> addresses = new ArrayList<>();
141         // Get IPv4 addresses from all network interfaces
142         if (null != networkInterfaces) {
143             while (networkInterfaces.hasNext()) {
144                 NetworkInterface currentNetworkInterface = networkInterfaces.next();
145                 Iterator<InetAddress> inetAddresses = currentNetworkInterface.getInetAddresses().asIterator();
146                 while (inetAddresses.hasNext()) {
147                     InetAddress currentAddress = inetAddresses.next();
148                     if (currentAddress instanceof Inet4Address && !currentAddress.isLoopbackAddress()) {
149                         addresses.add(currentAddress);
150                     }
151                 }
152             }
153         }
154         return addresses;
155     }
156
157     /**
158      * This method will find any active host in the network and return a list of them
159      * 
160      * @param addresses
161      * @return List of hosts
162      * @throws UnknownHostException
163      * @throws IOException
164      */
165     private List<InetAddress> findActiveHosts(List<InetAddress> addresses) throws UnknownHostException, IOException {
166         List<InetAddress> hosts = new ArrayList<>();
167         for (InetAddress inetAddress : addresses) {
168             String[] addressStrings = inetAddress.getHostAddress().split("[.]");
169             String subnet = addressStrings[0] + "." + addressStrings[1] + "." + addressStrings[2];
170             int timeout = 50;
171             for (int i = 0; i < 255; i++) {
172                 String host = subnet + "." + i;
173                 if (!inetAddress.getHostAddress().equals(host)) {
174                     if (InetAddress.getByName(host).isReachable(timeout)) {
175                         hosts.add(InetAddress.getByName(host));
176                     }
177                 }
178             }
179         }
180         return hosts;
181     }
182
183     /**
184      * This method builds a thing based on the response from the device
185      * 
186      * @param response
187      */
188     private void buildDiscoveryResult(CommData response, Boolean isHostname) {
189         ThingUID thingUID = new ThingUID(THING_TYPE_LIQUID_CHECK, response.payload.device.uuid);
190         DiscoveryResult dResult = DiscoveryResultBuilder.create(thingUID)
191                 .withProperties(response.createPropertyMap(isHostname)).withLabel(response.payload.device.name).build();
192         thingDiscovered(dResult);
193     }
194 }