]> git.basschouten.com Git - openhab-addons.git/blob
45a5fda805b5d7307685064a444f2cf079735ecc
[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.globalcache.internal.discovery;
14
15 import static org.openhab.binding.globalcache.internal.GlobalCacheBindingConstants.*;
16
17 import java.io.IOException;
18 import java.net.SocketException;
19 import java.util.HashMap;
20 import java.util.Map;
21 import java.util.Set;
22 import java.util.concurrent.Executors;
23 import java.util.concurrent.ScheduledExecutorService;
24 import java.util.concurrent.ScheduledFuture;
25 import java.util.concurrent.TimeUnit;
26
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.Thing;
32 import org.openhab.core.thing.ThingTypeUID;
33 import org.openhab.core.thing.ThingUID;
34 import org.osgi.service.component.annotations.Component;
35 import org.osgi.service.component.annotations.Modified;
36 import org.osgi.service.component.annotations.Reference;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 /**
41  * The {@link GlobalCacheDiscoveryService} class implements a service
42  * for discovering the GlobalCache devices.
43  *
44  * @author Mark Hilbush - Initial contribution
45  */
46 @Component(service = DiscoveryService.class, configurationPid = "discovery.globalcache")
47 public class GlobalCacheDiscoveryService extends AbstractDiscoveryService {
48     private final Logger logger = LoggerFactory.getLogger(GlobalCacheDiscoveryService.class);
49
50     private ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
51     private ScheduledFuture<?> gcDiscoveryJob;
52
53     // Discovery parameters
54     public static final boolean BACKGROUND_DISCOVERY_ENABLED = true;
55     public static final int BACKGROUND_DISCOVERY_DELAY = 10;
56
57     private NetworkAddressService networkAddressService;
58
59     private boolean terminate;
60
61     public GlobalCacheDiscoveryService() {
62         super(SUPPORTED_THING_TYPES_UIDS, 0, BACKGROUND_DISCOVERY_ENABLED);
63         gcDiscoveryJob = null;
64         terminate = false;
65     }
66
67     @Override
68     public Set<ThingTypeUID> getSupportedThingTypes() {
69         return SUPPORTED_THING_TYPES_UIDS;
70     }
71
72     @Override
73     protected void activate(Map<String, Object> configProperties) {
74         logger.debug("Globalcache discovery service activated");
75         super.activate(configProperties);
76     }
77
78     @Override
79     protected void deactivate() {
80         logger.debug("Globalcache discovery service deactivated");
81         stopBackgroundDiscovery();
82         super.deactivate();
83     }
84
85     @Override
86     @Modified
87     protected void modified(Map<String, Object> configProperties) {
88         super.modified(configProperties);
89     }
90
91     @Override
92     protected void startBackgroundDiscovery() {
93         if (gcDiscoveryJob == null) {
94             terminate = false;
95             logger.debug("Starting background discovery job in {} seconds", BACKGROUND_DISCOVERY_DELAY);
96             gcDiscoveryJob = scheduledExecutorService.schedule(this::discover, BACKGROUND_DISCOVERY_DELAY,
97                     TimeUnit.SECONDS);
98         }
99     }
100
101     @Override
102     protected void stopBackgroundDiscovery() {
103         if (gcDiscoveryJob != null) {
104             logger.debug("Canceling background discovery job");
105             terminate = true;
106             gcDiscoveryJob.cancel(false);
107             gcDiscoveryJob = null;
108         }
109     }
110
111     @Override
112     public void startScan() {
113     }
114
115     @Override
116     public void stopScan() {
117     }
118
119     private synchronized void discover() {
120         logger.debug("Discovery job is running");
121
122         MulticastListener gcMulticastListener;
123
124         try {
125             gcMulticastListener = new MulticastListener(networkAddressService.getPrimaryIpv4HostAddress());
126         } catch (SocketException se) {
127             logger.error("Discovery job got Socket exception creating multicast socket: {}", se.getMessage());
128             return;
129         } catch (IOException ioe) {
130             logger.error("Discovery job got IO exception creating multicast socket: {}", ioe.getMessage());
131             return;
132         }
133
134         while (!terminate) {
135             boolean beaconReceived;
136             try {
137                 // Wait for a discovery beacon.
138                 beaconReceived = gcMulticastListener.waitForBeacon();
139             } catch (IOException ioe) {
140                 logger.debug("Discovery job got exception waiting for beacon: {}", ioe.getMessage());
141                 beaconReceived = false;
142             }
143
144             if (beaconReceived) {
145                 // We got a discovery beacon. Process it as a potential new thing
146                 Map<String, Object> properties = new HashMap<>();
147
148                 properties.put(THING_PROPERTY_IP, gcMulticastListener.getIPAddress());
149                 properties.put(THING_PROPERTY_MAC, gcMulticastListener.getMACAddress());
150                 properties.put(THING_PROPERTY_UID, gcMulticastListener.getUID());
151                 properties.put(Thing.PROPERTY_VENDOR, gcMulticastListener.getVendor());
152                 properties.put(Thing.PROPERTY_MODEL_ID, gcMulticastListener.getModel());
153                 properties.put(Thing.PROPERTY_FIRMWARE_VERSION, gcMulticastListener.getSoftwareRevision());
154                 properties.put(Thing.PROPERTY_HARDWARE_VERSION, gcMulticastListener.getHardwareRevision());
155                 properties.put(Thing.PROPERTY_SERIAL_NUMBER, gcMulticastListener.getSerialNumber());
156
157                 logger.trace("Device of type {} discovered with MAC {} and IP {}", gcMulticastListener.getModel(),
158                         gcMulticastListener.getMACAddress(), gcMulticastListener.getIPAddress());
159
160                 ThingTypeUID typeUID = gcMulticastListener.getThingTypeUID();
161                 if (typeUID != null) {
162                     ThingUID uid = new ThingUID(typeUID, gcMulticastListener.getSerialNumber());
163                     logger.trace("Creating discovery result for: {}, type={}, IP={}", uid,
164                             gcMulticastListener.getModel(), gcMulticastListener.getIPAddress());
165                     thingDiscovered(DiscoveryResultBuilder.create(uid).withProperties(properties)
166                             .withRepresentationProperty(THING_PROPERTY_MAC)
167                             .withLabel(gcMulticastListener.getVendor() + " " + gcMulticastListener.getModel()).build());
168                 }
169             }
170         }
171         gcMulticastListener.shutdown();
172         logger.debug("Discovery job is exiting");
173     }
174
175     @Reference
176     protected void setNetworkAddressService(NetworkAddressService networkAddressService) {
177         this.networkAddressService = networkAddressService;
178     }
179
180     protected void unsetNetworkAddressService(NetworkAddressService networkAddressService) {
181         this.networkAddressService = null;
182     }
183 }