2 * Copyright (c) 2010-2022 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
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
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.zway.internal.discovery;
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;
23 import java.util.Enumeration;
24 import java.util.regex.Pattern;
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;
38 * The {@link ZWayBridgeDiscoveryService} is responsible for device discovery.
40 * @author Patrick Hecker - Initial contribution
42 @Component(service = DiscoveryService.class, configurationPid = "discovery.zway")
43 public class ZWayBridgeDiscoveryService extends AbstractDiscoveryService {
45 private final Logger logger = LoggerFactory.getLogger(getClass());
47 private static final int SEARCH_TIME = 240;
49 public ZWayBridgeDiscoveryService() {
50 super(ZWayBindingConstants.SUPPORTED_DEVICE_THING_TYPES_UIDS, SEARCH_TIME);
51 logger.debug("Initializing ZWayBridgeDiscoveryService");
55 logger.debug("Starting scan for Z-Way Server");
57 ValidateIPV4 validator = new ValidateIPV4();
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();
69 logger.debug("Scan IP address for Z-Way Server: {}", ipAddress);
71 // Search on localhost first
72 scheduler.execute(new ZWayServerScan(ipAddress));
74 String subnet = ipAddress + "/" + prefix;
75 SubnetUtils utils = new SubnetUtils(subnet);
76 String[] addresses = utils.getInfo().getAllAddresses();
78 for (String addressInSubnet : addresses) {
79 scheduler.execute(new ZWayServerScan(addressInSubnet));
85 } catch (SocketException e) {
86 logger.warn("Error occurred while searching Z-Way servers ({})", e.getMessage());
90 public boolean pingHost(String host, int port, int timeout) {
91 try (Socket socket = new Socket()) {
92 socket.connect(new InetSocketAddress(host, port), timeout);
94 } catch (IOException e) {
95 return false; // Either timeout or unreachable or failed DNS lookup.
99 public class ZWayServerScan implements Runnable {
100 private String ipAddress;
102 public ZWayServerScan(String ipAddress) {
103 this.ipAddress = ipAddress;
108 if (!pingHost(ipAddress, 8083, 500)) {
109 return; // Error occurred while searching Z-Way servers (Unreachable)
113 URL url = new URL("http://" + ipAddress + ":8083/ZAutomation/api/v1/status");
114 HttpURLConnection connection = (HttpURLConnection) url.openConnection();
116 if (connection.getResponseCode() == 401) {
117 ThingUID thingUID = new ThingUID(ZWayBindingConstants.THING_TYPE_BRIDGE,
118 ipAddress.replaceAll("\\.", "_"));
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);
127 } catch (Exception e) {
128 logger.warn("Discovery resulted in an unexpected exception", e);
134 protected void startScan() {
139 protected synchronized void stopScan() {
141 removeOlderResults(getTimestampOfLastScan());
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);
148 public boolean isValidIPV4(final String s) {
149 return ipV4Pattern.matcher(s).matches();