]> git.basschouten.com Git - openhab-addons.git/blob
93de7e2467b65f6587e7b811ff81b7688aec3ed2
[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.plclogo.internal.discovery;
14
15 import static org.openhab.binding.plclogo.internal.PLCLogoBindingConstants.THING_TYPE_DEVICE;
16
17 import java.io.IOException;
18 import java.net.Inet4Address;
19 import java.net.InetAddress;
20 import java.net.InterfaceAddress;
21 import java.net.NetworkInterface;
22 import java.net.SocketException;
23 import java.util.Arrays;
24 import java.util.Collections;
25 import java.util.Enumeration;
26 import java.util.Set;
27 import java.util.TreeSet;
28 import java.util.concurrent.ExecutorService;
29 import java.util.concurrent.Executors;
30 import java.util.concurrent.RejectedExecutionException;
31 import java.util.concurrent.TimeUnit;
32 import java.util.concurrent.locks.ReentrantLock;
33
34 import org.apache.commons.net.util.SubnetUtils;
35 import org.eclipse.jdt.annotation.NonNullByDefault;
36 import org.openhab.core.config.discovery.AbstractDiscoveryService;
37 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
38 import org.openhab.core.config.discovery.DiscoveryService;
39 import org.openhab.core.model.script.actions.Ping;
40 import org.openhab.core.thing.ThingTypeUID;
41 import org.openhab.core.thing.ThingUID;
42 import org.osgi.service.component.annotations.Component;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45
46 /**
47  * The {@link PLCDiscoveryService} is responsible for discovering devices on
48  * the current Network. It uses every Network Interface which is connected to a network.
49  * Based on network binding discovery service.
50  *
51  * @author Alexander Falkenstern - Initial contribution
52  */
53 @NonNullByDefault
54 @Component(service = DiscoveryService.class)
55 public class PLCDiscoveryService extends AbstractDiscoveryService {
56
57     private final Logger logger = LoggerFactory.getLogger(PLCDiscoveryService.class);
58     private static final Set<ThingTypeUID> THING_TYPES_UIDS = Collections.singleton(THING_TYPE_DEVICE);
59
60     private static final String LOGO_HOST = "address";
61     private static final int LOGO_PORT = 102;
62
63     private static final int CONNECTION_TIMEOUT = 500;
64     private static final int DISCOVERY_TIMEOUT = 30;
65
66     private class Runner implements Runnable {
67         private final ReentrantLock lock = new ReentrantLock();
68         private String host;
69
70         public Runner(final String address) {
71             this.host = address;
72         }
73
74         @Override
75         public void run() {
76             try {
77                 if (Ping.checkVitality(host, LOGO_PORT, CONNECTION_TIMEOUT)) {
78                     logger.debug("LOGO! device found at: {}.", host);
79
80                     ThingUID thingUID = new ThingUID(THING_TYPE_DEVICE, host.replace('.', '_'));
81                     DiscoveryResultBuilder builder = DiscoveryResultBuilder.create(thingUID);
82                     builder.withProperty(LOGO_HOST, host);
83                     builder.withLabel(host);
84
85                     lock.lock();
86                     try {
87                         thingDiscovered(builder.build());
88                     } finally {
89                         lock.unlock();
90                     }
91                 }
92             } catch (IOException exception) {
93                 logger.debug("LOGO! device not found at: {}.", host);
94             }
95         }
96     }
97
98     /**
99      * Constructor.
100      */
101     public PLCDiscoveryService() {
102         super(THING_TYPES_UIDS, DISCOVERY_TIMEOUT);
103     }
104
105     @Override
106     protected void startScan() {
107         stopScan();
108
109         logger.debug("Start scan for LOGO! bridge");
110
111         Enumeration<NetworkInterface> devices = null;
112         try {
113             devices = NetworkInterface.getNetworkInterfaces();
114         } catch (SocketException exception) {
115             logger.warn("LOGO! bridge discovering: {}.", exception.toString());
116         }
117
118         Set<String> addresses = new TreeSet<>();
119         while ((devices != null) && devices.hasMoreElements()) {
120             NetworkInterface device = devices.nextElement();
121             try {
122                 if (!device.isUp() || device.isLoopback()) {
123                     continue;
124                 }
125             } catch (SocketException exception) {
126                 logger.warn("LOGO! bridge discovering: {}.", exception.toString());
127             }
128             for (InterfaceAddress iface : device.getInterfaceAddresses()) {
129                 InetAddress address = iface.getAddress();
130                 if (address instanceof Inet4Address) {
131                     String prefix = String.valueOf(iface.getNetworkPrefixLength());
132                     SubnetUtils utilities = new SubnetUtils(address.getHostAddress() + "/" + prefix);
133                     addresses.addAll(Arrays.asList(utilities.getInfo().getAllAddresses()));
134                 }
135             }
136         }
137
138         ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
139         for (String address : addresses) {
140             try {
141                 executor.execute(new Runner(address));
142             } catch (RejectedExecutionException exception) {
143                 logger.warn("LOGO! bridge discovering: {}.", exception.toString());
144             }
145         }
146
147         try {
148             executor.awaitTermination(CONNECTION_TIMEOUT * addresses.size(), TimeUnit.MILLISECONDS);
149         } catch (InterruptedException exception) {
150             logger.warn("LOGO! bridge discovering: {}.", exception.toString());
151         }
152         executor.shutdown();
153
154         stopScan();
155     }
156
157     @Override
158     protected synchronized void stopScan() {
159         logger.debug("Stop scan for LOGO! bridge");
160         super.stopScan();
161     }
162 }