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