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