]> git.basschouten.com Git - openhab-addons.git/blob
001757e3c44c8d947ac6645a234b1e9995efa651
[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.mqtt.discovery;
14
15 import java.util.Date;
16 import java.util.Set;
17 import java.util.concurrent.ScheduledFuture;
18 import java.util.concurrent.TimeUnit;
19 import java.util.concurrent.atomic.AtomicBoolean;
20
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.eclipse.jdt.annotation.Nullable;
23 import org.openhab.core.config.discovery.AbstractDiscoveryService;
24 import org.openhab.core.thing.ThingTypeUID;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
27
28 /**
29  * Base MQTT discovery class. Responsible for connecting to the {@link MQTTTopicDiscoveryService}.
30  *
31  * Implement MQTT discovery services on top of this. You still need to reference
32  * the MQTTTopicDiscoveryService like in:
33  *
34  * <pre>
35  * &#64;NonNullByDefault({})
36  * &#64;Reference
37  * protected MQTTTopicDiscoveryService mqttTopicDiscovery;
38  * </pre>
39  *
40  * @author David Graeff - Initial contribution
41  */
42 @NonNullByDefault
43 public abstract class AbstractMQTTDiscovery extends AbstractDiscoveryService implements MQTTTopicDiscoveryParticipant {
44     private final Logger logger = LoggerFactory.getLogger(AbstractMQTTDiscovery.class);
45
46     protected final String subscribeTopic;
47
48     private int timeout;
49
50     private @Nullable ScheduledFuture<?> scheduledStop;
51
52     private AtomicBoolean isSubscribed;
53
54     public AbstractMQTTDiscovery(@Nullable Set<ThingTypeUID> supportedThingTypes, int timeout,
55             boolean backgroundDiscoveryEnabledByDefault, String baseTopic) {
56         super(supportedThingTypes, 0, backgroundDiscoveryEnabledByDefault);
57         this.subscribeTopic = baseTopic;
58         this.timeout = timeout;
59         isSubscribed = new AtomicBoolean(false);
60     }
61
62     /**
63      * Only subscribe if we were not already subscribed
64      */
65     private void subscribe() {
66         if (!isSubscribed.getAndSet(true)) {
67             getDiscoveryService().subscribe(this, subscribeTopic);
68         }
69     }
70
71     /**
72      * Only unsubscribe if we were already subscribed
73      */
74     private void unSubscribe() {
75         if (isSubscribed.getAndSet(false)) {
76             getDiscoveryService().unsubscribe(this);
77         }
78     }
79
80     /**
81      * Return the topic discovery service.
82      */
83     protected abstract MQTTTopicDiscoveryService getDiscoveryService();
84
85     private synchronized void stopTimeout() {
86         if (scheduledStop != null) {
87             scheduledStop.cancel(false);
88             scheduledStop = null;
89         }
90     }
91
92     protected synchronized void resetTimeout() {
93         stopTimeout();
94
95         // schedule an automatic call of stopScan when timeout is reached
96         if (timeout > 0) {
97             Runnable runnable = new Runnable() {
98                 @Override
99                 public void run() {
100                     try {
101                         stopScan();
102                     } catch (Exception e) {
103                         logger.debug("Exception occurred during execution: {}", e.getMessage(), e);
104                     }
105                 }
106             };
107
108             scheduledStop = scheduler.schedule(runnable, timeout, TimeUnit.SECONDS);
109         }
110     }
111
112     @Override
113     protected void startScan() {
114         if (isBackgroundDiscoveryEnabled()) {
115             super.stopScan();
116             return;
117         }
118         resetTimeout();
119         subscribe();
120     }
121
122     @Override
123     protected synchronized void stopScan() {
124         if (isBackgroundDiscoveryEnabled()) {
125             super.stopScan();
126             return;
127         }
128         stopTimeout();
129         unSubscribe();
130         super.stopScan();
131     }
132
133     @Override
134     public synchronized void abortScan() {
135         stopTimeout();
136         super.abortScan();
137     }
138
139     @Override
140     protected void startBackgroundDiscovery() {
141         // Remove results that are restored after a restart
142         removeOlderResults(new Date().getTime());
143         subscribe();
144     }
145
146     @Override
147     protected void stopBackgroundDiscovery() {
148         unSubscribe();
149     }
150 }