]> git.basschouten.com Git - openhab-addons.git/blob
03d1450c72f2aebbb395bc5ab2335cf4c2dc879c
[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.wifiled.internal.discovery;
14
15 import static org.openhab.binding.wifiled.internal.WiFiLEDBindingConstants.*;
16
17 import java.io.IOException;
18 import java.net.DatagramPacket;
19 import java.net.DatagramSocket;
20 import java.net.InetAddress;
21 import java.net.SocketTimeoutException;
22 import java.util.HashMap;
23 import java.util.Map;
24 import java.util.Set;
25 import java.util.concurrent.TimeUnit;
26
27 import org.openhab.binding.wifiled.internal.handler.AbstractWiFiLEDDriver;
28 import org.openhab.binding.wifiled.internal.handler.ClassicWiFiLEDDriver;
29 import org.openhab.core.config.discovery.AbstractDiscoveryService;
30 import org.openhab.core.config.discovery.DiscoveryResult;
31 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
32 import org.openhab.core.config.discovery.DiscoveryService;
33 import org.openhab.core.thing.ThingTypeUID;
34 import org.openhab.core.thing.ThingUID;
35 import org.osgi.service.component.annotations.Component;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39 /**
40  * The {@link WiFiLEDDiscoveryService} class implements a service
41  * for discovering supported WiFi LED Devices.
42  *
43  * @author Osman Basha - Initial contribution
44  */
45 @Component(service = DiscoveryService.class, configurationPid = "discovery.wifiled")
46 public class WiFiLEDDiscoveryService extends AbstractDiscoveryService {
47
48     private static final int DEFAULT_BROADCAST_PORT = 48899;
49     private static final String DISCOVER_MESSAGE = "HF-A11ASSISTHREAD";
50     private Logger logger = LoggerFactory.getLogger(WiFiLEDDiscoveryService.class);
51
52     public WiFiLEDDiscoveryService() {
53         super(SUPPORTED_THING_TYPES_UIDS, 15, true);
54     }
55
56     @Override
57     public Set<ThingTypeUID> getSupportedThingTypes() {
58         return SUPPORTED_THING_TYPES_UIDS;
59     }
60
61     @Override
62     protected void startBackgroundDiscovery() {
63         logger.debug("Start WiFi LED background discovery");
64         scheduler.schedule(() -> discover(), 0, TimeUnit.SECONDS);
65     }
66
67     @Override
68     public void startScan() {
69         logger.debug("Start WiFi LED scan");
70         discover();
71     }
72
73     private synchronized void discover() {
74         logger.debug("Try to discover all WiFi LED devices");
75
76         try (DatagramSocket socket = new DatagramSocket(DEFAULT_BROADCAST_PORT)) {
77             socket.setBroadcast(true);
78             socket.setSoTimeout(5000);
79
80             InetAddress inetAddress = InetAddress.getByName("255.255.255.255");
81
82             // send discover
83             byte[] discover = DISCOVER_MESSAGE.getBytes();
84             DatagramPacket packet = new DatagramPacket(discover, discover.length, inetAddress, DEFAULT_BROADCAST_PORT);
85             socket.send(packet);
86             logger.debug("Discover message sent: '{}'", DISCOVER_MESSAGE);
87
88             // wait for responses
89             while (true) {
90                 byte[] rxbuf = new byte[256];
91                 packet = new DatagramPacket(rxbuf, rxbuf.length);
92                 try {
93                     socket.receive(packet);
94                 } catch (SocketTimeoutException e) {
95                     logger.trace("Timeout exceeded. Discovery process ended.");
96                     break;
97                 }
98
99                 byte[] data = packet.getData();
100                 String s = bytesToString(data);
101                 logger.debug("Discovery response received: '{}' [{}] ", s, ClassicWiFiLEDDriver.bytesToHex(data));
102
103                 // 192.168.178.25,ACCF23489C9A,HF-LPB100-ZJ200
104                 // ^-IP..........,^-MAC.......,^-HOSTNAME.....
105
106                 String[] ss = s.split(",");
107                 if (ss.length < 3) {
108                     logger.debug("Ignoring unparseable discovery response: '{}'", s);
109                     continue;
110                 }
111
112                 String ip = ss[0];
113                 String mac = ss[1];
114                 String name = ss[2];
115                 logger.debug("Adding a new WiFi LED with IP '{}' and MAC '{}' to inbox", ip, mac);
116                 Map<String, Object> properties = new HashMap<>();
117                 properties.put("ip", ip);
118                 properties.put("protocol", AbstractWiFiLEDDriver.Protocol.LD382A);
119                 ThingUID uid = new ThingUID(THING_TYPE_WIFILED, mac);
120
121                 DiscoveryResult result = DiscoveryResultBuilder.create(uid).withProperties(properties).withLabel(name)
122                         .build();
123                 thingDiscovered(result);
124                 logger.debug("Thing discovered '{}'", result);
125             }
126         } catch (IOException e) {
127             logger.debug("Device discovery encountered an I/O Exception: {}", e.getMessage(), e);
128         }
129     }
130
131     private static String bytesToString(byte[] bytes) {
132         StringBuilder sb = new StringBuilder();
133         for (byte aByte : bytes) {
134             if (aByte == 0) {
135                 break;
136             }
137             sb.append((char) (aByte & 0xFF));
138         }
139
140         return sb.toString();
141     }
142 }