2 * Copyright (c) 2010-2024 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.Enumeration;
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;
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;
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.
50 * @author Alexander Falkenstern - Initial contribution
53 @Component(service = DiscoveryService.class)
54 public class PLCDiscoveryService extends AbstractDiscoveryService {
56 private final Logger logger = LoggerFactory.getLogger(PLCDiscoveryService.class);
57 private static final Set<ThingTypeUID> THING_TYPES_UIDS = Set.of(THING_TYPE_DEVICE);
59 private static final String LOGO_HOST = "address";
60 private static final int LOGO_PORT = 102;
62 private static final int CONNECTION_TIMEOUT = 500;
63 private static final int DISCOVERY_TIMEOUT = 30;
65 private class Runner implements Runnable {
66 private final ReentrantLock lock = new ReentrantLock();
69 public Runner(final String address) {
76 if (Ping.checkVitality(host, LOGO_PORT, CONNECTION_TIMEOUT)) {
77 logger.debug("LOGO! device found at: {}.", host);
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);
86 thingDiscovered(builder.build());
91 } catch (IOException exception) {
92 logger.debug("LOGO! device not found at: {}.", host);
100 public PLCDiscoveryService() {
101 super(THING_TYPES_UIDS, DISCOVERY_TIMEOUT);
105 protected void startScan() {
108 logger.debug("Start scan for LOGO! bridge");
110 Enumeration<NetworkInterface> devices = null;
112 devices = NetworkInterface.getNetworkInterfaces();
113 } catch (SocketException exception) {
114 logger.warn("LOGO! bridge discovering: {}.", exception.toString());
117 Set<String> addresses = new TreeSet<>();
118 while ((devices != null) && devices.hasMoreElements()) {
119 NetworkInterface device = devices.nextElement();
121 if (!device.isUp() || device.isLoopback()) {
124 } catch (SocketException exception) {
125 logger.warn("LOGO! bridge discovering: {}.", exception.toString());
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()));
137 ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
138 for (String address : addresses) {
140 executor.execute(new Runner(address));
141 } catch (RejectedExecutionException exception) {
142 logger.warn("LOGO! bridge discovering: {}.", exception.toString());
147 executor.awaitTermination(CONNECTION_TIMEOUT * addresses.size(), TimeUnit.MILLISECONDS);
148 } catch (InterruptedException exception) {
149 logger.warn("LOGO! bridge discovering: {}.", exception.toString());
157 protected synchronized void stopScan() {
158 logger.debug("Stop scan for LOGO! bridge");