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.homematic.internal.discovery;
15 import static org.openhab.binding.homematic.internal.HomematicBindingConstants.THING_TYPE_BRIDGE;
17 import java.io.IOException;
18 import java.net.DatagramPacket;
19 import java.net.InetAddress;
20 import java.net.MulticastSocket;
21 import java.net.SocketTimeoutException;
22 import java.util.Collections;
23 import java.util.concurrent.Future;
25 import org.openhab.binding.homematic.internal.discovery.eq3udp.Eq3UdpRequest;
26 import org.openhab.binding.homematic.internal.discovery.eq3udp.Eq3UdpResponse;
27 import org.openhab.core.config.discovery.AbstractDiscoveryService;
28 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
29 import org.openhab.core.config.discovery.DiscoveryService;
30 import org.openhab.core.net.NetworkAddressService;
31 import org.openhab.core.thing.ThingUID;
32 import org.osgi.service.component.annotations.Component;
33 import org.osgi.service.component.annotations.Reference;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
38 * Discovers Homematic CCU's and adds the results to the inbox.
40 * @author Gerhard Riegler - Initial contribution
42 @Component(service = DiscoveryService.class, configurationPid = "discovery.homematic")
43 public class CcuDiscoveryService extends AbstractDiscoveryService {
44 private final Logger logger = LoggerFactory.getLogger(CcuDiscoveryService.class);
46 private static final int RECEIVE_TIMEOUT_MSECS = 3000;
47 private InetAddress broadcastAddress;
48 private MulticastSocket socket;
49 private Future<?> scanFuture;
50 private NetworkAddressService networkAddressService;
52 public CcuDiscoveryService() {
53 super(Collections.singleton(THING_TYPE_BRIDGE), 5, true);
57 protected void startScan() {
58 if (scanFuture == null) {
59 scanFuture = scheduler.submit(this::startDiscovery);
61 logger.debug("Homematic CCU background discovery scan in progress");
66 protected void stopScan() {
67 if (scanFuture != null) {
68 scanFuture.cancel(false);
74 protected void startBackgroundDiscovery() {
75 // only start once at startup
80 protected void stopBackgroundDiscovery() {
84 private synchronized void startDiscovery() {
86 logger.debug("Starting Homematic CCU discovery scan");
87 String configuredBroadcastAddress = networkAddressService.getConfiguredBroadcastAddress();
88 if (configuredBroadcastAddress != null) {
89 broadcastAddress = InetAddress.getByName(configuredBroadcastAddress);
91 if (broadcastAddress == null) {
92 logger.warn("Homematic CCU discovery: discovery not possible, no broadcast address found");
95 socket = new MulticastSocket();
96 socket.setBroadcast(true);
97 socket.setTimeToLive(5);
98 socket.setSoTimeout(800);
102 } catch (Exception ex) {
103 logger.error("An error was thrown while running Homematic CCU discovery {}", ex.getMessage(), ex);
110 * Sends a UDP hello broadcast message for CCU gateways.
112 private void sendBroadcast() throws IOException {
113 Eq3UdpRequest hello = new Eq3UdpRequest();
114 byte[] data = hello.getBytes();
115 DatagramPacket packet = new DatagramPacket(data, data.length, broadcastAddress, 43439);
120 * Receives the UDP responses to the hello messages.
122 private void receiveResponses() throws IOException {
123 long startTime = System.currentTimeMillis();
124 long currentTime = System.currentTimeMillis();
125 while (currentTime - startTime < RECEIVE_TIMEOUT_MSECS) {
126 extractGatewayInfos();
127 currentTime = System.currentTimeMillis();
133 * Extracts the CCU infos from the UDP response.
135 private void extractGatewayInfos() throws IOException {
137 DatagramPacket packet = new DatagramPacket(new byte[265], 256);
138 socket.receive(packet);
140 Eq3UdpResponse response = new Eq3UdpResponse(packet.getData());
141 logger.trace("Eq3UdpResponse: {}", response);
142 if (response.isValid()) {
143 logger.debug("Discovered a CCU gateway with serial number '{}'", response.getSerialNumber());
145 String address = packet.getAddress().getHostAddress();
146 ThingUID thingUid = new ThingUID(THING_TYPE_BRIDGE, response.getSerialNumber());
147 thingDiscovered(DiscoveryResultBuilder.create(thingUid).withProperty("gatewayAddress", address)
148 .withRepresentationProperty("gatewayAddress")
149 .withLabel(response.getDeviceTypeId() + " - " + address).build());
151 } catch (SocketTimeoutException ex) {
157 protected void setNetworkAddressService(NetworkAddressService networkAddressService) {
158 this.networkAddressService = networkAddressService;
161 protected void unsetNetworkAddressService(NetworkAddressService networkAddressService) {
162 this.networkAddressService = null;