]> git.basschouten.com Git - openhab-addons.git/blob
cd5bf0f6e8a9d6c5d47a088a5618207d749c27a4
[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.benqprojector.internal.discovery;
14
15 import static org.openhab.binding.benqprojector.internal.BenqProjectorBindingConstants.*;
16
17 import java.io.IOException;
18 import java.util.Map;
19 import java.util.Set;
20 import java.util.concurrent.ScheduledFuture;
21 import java.util.concurrent.TimeUnit;
22
23 import org.eclipse.jdt.annotation.NonNullByDefault;
24 import org.eclipse.jdt.annotation.Nullable;
25 import org.openhab.core.config.discovery.AbstractDiscoveryService;
26 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
27 import org.openhab.core.config.discovery.DiscoveryService;
28 import org.openhab.core.i18n.LocaleProvider;
29 import org.openhab.core.i18n.TranslationProvider;
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.framework.Bundle;
35 import org.osgi.framework.FrameworkUtil;
36 import org.osgi.service.component.annotations.Activate;
37 import org.osgi.service.component.annotations.Component;
38 import org.osgi.service.component.annotations.Reference;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 /**
43  * The {@link BenqProjectorDiscoveryService} class implements a service
44  * for discovering BenQ projectors using the AMX Device Discovery protocol.
45  *
46  * @author Mark Hilbush - Initial contribution
47  * @author Michael Lobstein - Adapted for the BenQ Projector binding
48  */
49 @NonNullByDefault
50 @Component(service = DiscoveryService.class, configurationPid = "discovery.benqprojector")
51 public class BenqProjectorDiscoveryService extends AbstractDiscoveryService {
52     private final Logger logger = LoggerFactory.getLogger(BenqProjectorDiscoveryService.class);
53     private @Nullable ScheduledFuture<?> benqDiscoveryJob;
54
55     // Discovery parameters
56     public static final boolean BACKGROUND_DISCOVERY_ENABLED = true;
57     public static final int BACKGROUND_DISCOVERY_DELAY_TIMEOUT_SEC = 10;
58
59     private NetworkAddressService networkAddressService;
60     private final TranslationProvider translationProvider;
61     private final LocaleProvider localeProvider;
62     private final @Nullable Bundle bundle;
63
64     private boolean terminate = false;
65
66     @Activate
67     public BenqProjectorDiscoveryService(@Reference NetworkAddressService networkAddressService,
68             @Reference TranslationProvider translationProvider, @Reference LocaleProvider localeProvider) {
69         super(SUPPORTED_THING_TYPES_UIDS, 0, BACKGROUND_DISCOVERY_ENABLED);
70         this.networkAddressService = networkAddressService;
71         this.translationProvider = translationProvider;
72         this.localeProvider = localeProvider;
73         this.bundle = FrameworkUtil.getBundle(BenqProjectorDiscoveryService.class);
74
75         benqDiscoveryJob = null;
76         terminate = false;
77     }
78
79     @Override
80     public Set<ThingTypeUID> getSupportedThingTypes() {
81         return SUPPORTED_THING_TYPES_UIDS;
82     }
83
84     @Override
85     protected void startBackgroundDiscovery() {
86         if (benqDiscoveryJob == null) {
87             terminate = false;
88             logger.debug("Starting background discovery job in {} seconds", BACKGROUND_DISCOVERY_DELAY_TIMEOUT_SEC);
89             benqDiscoveryJob = scheduler.schedule(this::discover, BACKGROUND_DISCOVERY_DELAY_TIMEOUT_SEC,
90                     TimeUnit.SECONDS);
91         }
92     }
93
94     @Override
95     protected void stopBackgroundDiscovery() {
96         ScheduledFuture<?> benqDiscoveryJob = this.benqDiscoveryJob;
97         if (benqDiscoveryJob != null) {
98             terminate = true;
99             benqDiscoveryJob.cancel(false);
100             this.benqDiscoveryJob = null;
101         }
102     }
103
104     @Override
105     public void startScan() {
106     }
107
108     @Override
109     public void stopScan() {
110     }
111
112     private synchronized void discover() {
113         logger.debug("Discovery job is running");
114         MulticastListener benqMulticastListener;
115         String local = "127.0.0.1";
116
117         try {
118             String ip = networkAddressService.getPrimaryIpv4HostAddress();
119             benqMulticastListener = new MulticastListener((ip != null ? ip : local));
120         } catch (IOException ioe) {
121             logger.debug("Discovery job got IO exception creating multicast socket: {}", ioe.getMessage());
122             return;
123         }
124
125         while (!terminate) {
126             try {
127                 // Wait for a discovery beacon to return properties for a BenQ projector.
128                 Map<String, Object> thingProperties = benqMulticastListener.waitForBeacon();
129
130                 if (thingProperties != null) {
131                     // The MulticastListener found a projector, add it as new thing
132                     String uid = (String) thingProperties.get(Thing.PROPERTY_MAC_ADDRESS);
133                     String ipAddress = (String) thingProperties.get(THING_PROPERTY_HOST);
134
135                     if (uid != null) {
136                         logger.trace("Projector with UID {} discovered at IP: {}", uid, ipAddress);
137
138                         ThingUID thingUid = new ThingUID(THING_TYPE_PROJECTOR_TCP, uid);
139                         logger.trace("Creating BenQ projector discovery result for: {}, IP={}", uid, ipAddress);
140                         thingDiscovered(
141                                 DiscoveryResultBuilder.create(thingUid).withProperties(thingProperties)
142                                         .withLabel(translationProvider.getText(bundle,
143                                                 "thing-type.benqprojector.discovery.label", "BenQ Projector",
144                                                 localeProvider.getLocale()) + " " + uid)
145                                         .withRepresentationProperty(Thing.PROPERTY_MAC_ADDRESS).build());
146                     }
147                 }
148             } catch (IOException ioe) {
149                 logger.debug("Discovery job got exception waiting for beacon: {}", ioe.getMessage());
150             }
151         }
152         benqMulticastListener.shutdown();
153         logger.debug("Discovery job is exiting");
154     }
155 }