2 * Copyright (c) 2010-2023 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.plclogo.internal.discovery;
15 import static org.openhab.binding.plclogo.internal.PLCLogoBindingConstants.THING_TYPE_DEVICE;
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;
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;
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;
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.
51 * @author Alexander Falkenstern - Initial contribution
54 @Component(service = DiscoveryService.class)
55 public class PLCDiscoveryService extends AbstractDiscoveryService {
57 private final Logger logger = LoggerFactory.getLogger(PLCDiscoveryService.class);
58 private static final Set<ThingTypeUID> THING_TYPES_UIDS = Collections.singleton(THING_TYPE_DEVICE);
60 private static final String LOGO_HOST = "address";
61 private static final int LOGO_PORT = 102;
63 private static final int CONNECTION_TIMEOUT = 500;
64 private static final int DISCOVERY_TIMEOUT = 30;
66 private class Runner implements Runnable {
67 private final ReentrantLock lock = new ReentrantLock();
70 public Runner(final String address) {
77 if (Ping.checkVitality(host, LOGO_PORT, CONNECTION_TIMEOUT)) {
78 logger.debug("LOGO! device found at: {}.", host);
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);
87 thingDiscovered(builder.build());
92 } catch (IOException exception) {
93 logger.debug("LOGO! device not found at: {}.", host);
101 public PLCDiscoveryService() {
102 super(THING_TYPES_UIDS, DISCOVERY_TIMEOUT);
106 protected void startScan() {
109 logger.debug("Start scan for LOGO! bridge");
111 Enumeration<NetworkInterface> devices = null;
113 devices = NetworkInterface.getNetworkInterfaces();
114 } catch (SocketException exception) {
115 logger.warn("LOGO! bridge discovering: {}.", exception.toString());
118 Set<String> addresses = new TreeSet<>();
119 while ((devices != null) && devices.hasMoreElements()) {
120 NetworkInterface device = devices.nextElement();
122 if (!device.isUp() || device.isLoopback()) {
125 } catch (SocketException exception) {
126 logger.warn("LOGO! bridge discovering: {}.", exception.toString());
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()));
138 ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
139 for (String address : addresses) {
141 executor.execute(new Runner(address));
142 } catch (RejectedExecutionException exception) {
143 logger.warn("LOGO! bridge discovering: {}.", exception.toString());
148 executor.awaitTermination(CONNECTION_TIMEOUT * addresses.size(), TimeUnit.MILLISECONDS);
149 } catch (InterruptedException exception) {
150 logger.warn("LOGO! bridge discovering: {}.", exception.toString());
158 protected synchronized void stopScan() {
159 logger.debug("Stop scan for LOGO! bridge");