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.pjlinkdevice.internal.discovery;
15 import java.net.InetAddress;
16 import java.net.InterfaceAddress;
17 import java.net.NetworkInterface;
18 import java.net.SocketException;
19 import java.util.ArrayList;
20 import java.util.HashSet;
22 import java.util.concurrent.ExecutorService;
23 import java.util.concurrent.Executors;
24 import java.util.concurrent.TimeUnit;
26 import org.eclipse.jdt.annotation.NonNullByDefault;
27 import org.eclipse.jdt.annotation.Nullable;
28 import org.openhab.binding.pjlinkdevice.internal.PJLinkDeviceBindingConstants;
29 import org.openhab.core.config.discovery.AbstractDiscoveryService;
30 import org.openhab.core.thing.ThingTypeUID;
31 import org.openhab.core.thing.ThingUID;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
36 * Discovery of PJLink devices. Checks IP addresses in parallel processing.
38 * Generating IP addresses and checking them is done by the subclasses implementing
39 * {@link AbstractDiscoveryParticipant#generateAddressesToScan} and {@link AbstractDiscoveryParticipant#checkAddress}
41 * @author Nils Schnabel - Initial contribution
44 public abstract class AbstractDiscoveryParticipant extends AbstractDiscoveryService {
45 protected final Logger logger = LoggerFactory.getLogger(AbstractDiscoveryParticipant.class);
46 private Integer scannedIPcount = 0;
47 private @Nullable ExecutorService executorService = null;
49 public AbstractDiscoveryParticipant(Set<ThingTypeUID> supportedThingTypes, int timeout,
50 boolean backgroundDiscoveryEnabledByDefault) throws IllegalArgumentException {
51 super(supportedThingTypes, timeout, backgroundDiscoveryEnabledByDefault);
54 protected ExecutorService getExecutorService() {
55 ExecutorService executorService = this.executorService;
56 if (executorService == null) {
57 this.executorService = executorService = Executors
58 .newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2);
60 return executorService;
64 protected void startScan() {
65 logger.trace("PJLinkProjectorDiscoveryParticipant startScan");
66 Set<InetAddress> addressesToScan = generateAddressesToScan();
68 for (InetAddress ip : addressesToScan) {
69 getExecutorService().execute(() -> {
70 Thread.currentThread().setName("Discovery thread " + ip);
71 checkAddress(ip, PJLinkDeviceBindingConstants.DEFAULT_PORT,
72 PJLinkDeviceBindingConstants.DEFAULT_SCAN_TIMEOUT_SECONDS);
74 synchronized (scannedIPcount) {
76 logger.debug("Scanned {} of {} IPs", scannedIPcount, addressesToScan.size());
77 if (scannedIPcount == addressesToScan.size()) {
78 logger.debug("Scan of {} IPs successful", scannedIPcount);
87 protected synchronized void stopScan() {
89 ExecutorService executorService = this.executorService;
90 if (executorService == null) {
95 executorService.awaitTermination(10000, TimeUnit.MILLISECONDS);
96 } catch (InterruptedException e) {
97 Thread.currentThread().interrupt(); // Reset interrupt flag
99 executorService.shutdown();
100 this.executorService = null;
103 public static ThingUID createServiceUID(String ip, int tcpPort) {
104 // uid must not contains dots
105 return new ThingUID(PJLinkDeviceBindingConstants.THING_TYPE_PJLINK, ip.replace('.', '_') + "_" + tcpPort);
108 protected abstract void checkAddress(InetAddress ip, int tcpPort, int timeout);
110 private Set<InetAddress> generateAddressesToScan() {
112 Set<InetAddress> addressesToScan = new HashSet<>();
113 ArrayList<NetworkInterface> interfaces = java.util.Collections
114 .list(NetworkInterface.getNetworkInterfaces());
115 for (NetworkInterface networkInterface : interfaces) {
116 if (networkInterface.isLoopback() || !networkInterface.isUp()) {
119 for (InterfaceAddress i : networkInterface.getInterfaceAddresses()) {
120 collectAddressesToScan(addressesToScan, i);
123 return addressesToScan;
124 } catch (SocketException e) {
125 logger.debug("Could not enumerate network interfaces", e);
127 return new HashSet<>();
130 protected abstract void collectAddressesToScan(Set<InetAddress> addressesToScan, InterfaceAddress i);