]> git.basschouten.com Git - openhab-addons.git/blob
b6d7a69a70ebb94c8cea5049b18ec42b46a2bdb1
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 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.homematic.internal.discovery;
14
15 import static org.openhab.binding.homematic.internal.HomematicBindingConstants.THING_TYPE_BRIDGE;
16
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.Set;
23 import java.util.concurrent.Future;
24
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;
36
37 /**
38  * Discovers Homematic CCU's and adds the results to the inbox.
39  *
40  * @author Gerhard Riegler - Initial contribution
41  */
42 @Component(service = DiscoveryService.class, configurationPid = "discovery.homematic")
43 public class CcuDiscoveryService extends AbstractDiscoveryService {
44     private final Logger logger = LoggerFactory.getLogger(CcuDiscoveryService.class);
45
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;
51
52     public CcuDiscoveryService() {
53         super(Set.of(THING_TYPE_BRIDGE), 5, true);
54     }
55
56     @Override
57     protected void startScan() {
58         if (scanFuture == null) {
59             scanFuture = scheduler.submit(this::startDiscovery);
60         } else {
61             logger.debug("Homematic CCU background discovery scan in progress");
62         }
63     }
64
65     @Override
66     protected void stopScan() {
67         if (scanFuture != null) {
68             scanFuture.cancel(false);
69             scanFuture = null;
70         }
71     }
72
73     @Override
74     protected void startBackgroundDiscovery() {
75         // only start once at startup
76         startScan();
77     }
78
79     @Override
80     protected void stopBackgroundDiscovery() {
81         stopScan();
82     }
83
84     private synchronized void startDiscovery() {
85         try {
86             logger.debug("Starting Homematic CCU discovery scan");
87             String configuredBroadcastAddress = networkAddressService.getConfiguredBroadcastAddress();
88             if (configuredBroadcastAddress != null) {
89                 broadcastAddress = InetAddress.getByName(configuredBroadcastAddress);
90             }
91             if (broadcastAddress == null) {
92                 logger.warn("Homematic CCU discovery: discovery not possible, no broadcast address found");
93                 return;
94             }
95             socket = new MulticastSocket();
96             socket.setBroadcast(true);
97             socket.setTimeToLive(5);
98             socket.setSoTimeout(800);
99
100             sendBroadcast();
101             receiveResponses();
102         } catch (Exception ex) {
103             logger.error("An error was thrown while running Homematic CCU discovery {}", ex.getMessage(), ex);
104         } finally {
105             scanFuture = null;
106         }
107     }
108
109     /**
110      * Sends a UDP hello broadcast message for CCU gateways.
111      */
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);
116         socket.send(packet);
117     }
118
119     /**
120      * Receives the UDP responses to the hello messages.
121      */
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();
128         }
129         socket.close();
130     }
131
132     /**
133      * Extracts the CCU infos from the UDP response.
134      */
135     private void extractGatewayInfos() throws IOException {
136         try {
137             DatagramPacket packet = new DatagramPacket(new byte[265], 256);
138             socket.receive(packet);
139
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());
144
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());
150             }
151         } catch (SocketTimeoutException ex) {
152             // ignore
153         }
154     }
155
156     @Reference
157     protected void setNetworkAddressService(NetworkAddressService networkAddressService) {
158         this.networkAddressService = networkAddressService;
159     }
160
161     protected void unsetNetworkAddressService(NetworkAddressService networkAddressService) {
162         this.networkAddressService = null;
163     }
164 }