]> git.basschouten.com Git - openhab-addons.git/blob
c26d69013d879797ecfe5fd6b736206dd4bc577e
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2022 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.zway.internal.discovery;
14
15 import java.io.IOException;
16 import java.net.HttpURLConnection;
17 import java.net.InetSocketAddress;
18 import java.net.InterfaceAddress;
19 import java.net.NetworkInterface;
20 import java.net.Socket;
21 import java.net.SocketException;
22 import java.net.URL;
23 import java.util.Enumeration;
24 import java.util.regex.Pattern;
25
26 import org.apache.commons.net.util.SubnetUtils;
27 import org.openhab.binding.zway.internal.ZWayBindingConstants;
28 import org.openhab.core.config.discovery.AbstractDiscoveryService;
29 import org.openhab.core.config.discovery.DiscoveryResult;
30 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
31 import org.openhab.core.config.discovery.DiscoveryService;
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  * The {@link ZWayBridgeDiscoveryService} is responsible for device discovery.
39  *
40  * @author Patrick Hecker - Initial contribution
41  */
42 @Component(service = DiscoveryService.class, configurationPid = "discovery.zway")
43 public class ZWayBridgeDiscoveryService extends AbstractDiscoveryService {
44
45     private final Logger logger = LoggerFactory.getLogger(getClass());
46
47     private static final int SEARCH_TIME = 240;
48
49     public ZWayBridgeDiscoveryService() {
50         super(ZWayBindingConstants.SUPPORTED_DEVICE_THING_TYPES_UIDS, SEARCH_TIME);
51         logger.debug("Initializing ZWayBridgeDiscoveryService");
52     }
53
54     private void scan() {
55         logger.debug("Starting scan for Z-Way Server");
56
57         ValidateIPV4 validator = new ValidateIPV4();
58
59         try {
60             Enumeration<NetworkInterface> enumNetworkInterface = NetworkInterface.getNetworkInterfaces();
61             while (enumNetworkInterface.hasMoreElements()) {
62                 NetworkInterface networkInterface = enumNetworkInterface.nextElement();
63                 if (networkInterface.isUp() && !networkInterface.isVirtual() && !networkInterface.isLoopback()) {
64                     for (InterfaceAddress address : networkInterface.getInterfaceAddresses()) {
65                         if (validator.isValidIPV4(address.getAddress().getHostAddress())) {
66                             String ipAddress = address.getAddress().getHostAddress();
67                             Short prefix = address.getNetworkPrefixLength();
68
69                             logger.debug("Scan IP address for Z-Way Server: {}", ipAddress);
70
71                             // Search on localhost first
72                             scheduler.execute(new ZWayServerScan(ipAddress));
73
74                             String subnet = ipAddress + "/" + prefix;
75                             SubnetUtils utils = new SubnetUtils(subnet);
76                             String[] addresses = utils.getInfo().getAllAddresses();
77
78                             for (String addressInSubnet : addresses) {
79                                 scheduler.execute(new ZWayServerScan(addressInSubnet));
80                             }
81                         }
82                     }
83                 }
84             }
85         } catch (SocketException e) {
86             logger.warn("Error occurred while searching Z-Way servers ({})", e.getMessage());
87         }
88     }
89
90     public boolean pingHost(String host, int port, int timeout) {
91         try (Socket socket = new Socket()) {
92             socket.connect(new InetSocketAddress(host, port), timeout);
93             return true;
94         } catch (IOException e) {
95             return false; // Either timeout or unreachable or failed DNS lookup.
96         }
97     }
98
99     public class ZWayServerScan implements Runnable {
100         private String ipAddress;
101
102         public ZWayServerScan(String ipAddress) {
103             this.ipAddress = ipAddress;
104         }
105
106         @Override
107         public void run() {
108             if (!pingHost(ipAddress, 8083, 500)) {
109                 return; // Error occurred while searching Z-Way servers (Unreachable)
110             }
111
112             try {
113                 URL url = new URL("http://" + ipAddress + ":8083/ZAutomation/api/v1/status");
114                 HttpURLConnection connection = (HttpURLConnection) url.openConnection();
115
116                 if (connection.getResponseCode() == 401) {
117                     ThingUID thingUID = new ThingUID(ZWayBindingConstants.THING_TYPE_BRIDGE,
118                             ipAddress.replaceAll("\\.", "_"));
119
120                     // Attention: if is already present as thing in the ThingRegistry
121                     // the configuration for thing will be updated!
122                     DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID)
123                             .withProperty(ZWayBindingConstants.BRIDGE_CONFIG_ZWAY_SERVER_IP_ADDRESS, ipAddress)
124                             .withLabel("Z-Way Server " + ipAddress).build();
125                     thingDiscovered(discoveryResult);
126                 }
127             } catch (Exception e) {
128                 logger.warn("Discovery resulted in an unexpected exception", e);
129             }
130         }
131     }
132
133     @Override
134     protected void startScan() {
135         scan();
136     }
137
138     @Override
139     protected synchronized void stopScan() {
140         super.stopScan();
141         removeOlderResults(getTimestampOfLastScan());
142     }
143
144     class ValidateIPV4 {
145         private final String ipV4Regex = "^((0|1\\d?\\d?|2[0-4]?\\d?|25[0-5]?|[3-9]\\d?)\\.){3}(0|1\\d?\\d?|2[0-4]?\\d?|25[0-5]?|[3-9]\\d?)$";
146         private Pattern ipV4Pattern = Pattern.compile(ipV4Regex);
147
148         public boolean isValidIPV4(final String s) {
149             return ipV4Pattern.matcher(s).matches();
150         }
151     }
152 }