2 * Copyright (c) 2010-2020 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
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
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.velux.internal.discovery;
15 import static org.openhab.binding.velux.internal.VeluxBindingConstants.*;
17 import java.util.HashSet;
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.openhab.binding.velux.internal.VeluxBindingConstants;
22 import org.openhab.binding.velux.internal.VeluxBindingProperties;
23 import org.openhab.binding.velux.internal.handler.VeluxBridgeHandler;
24 import org.openhab.binding.velux.internal.things.VeluxProduct;
25 import org.openhab.binding.velux.internal.things.VeluxProductSerialNo;
26 import org.openhab.binding.velux.internal.things.VeluxScene;
27 import org.openhab.binding.velux.internal.utils.Localization;
28 import org.openhab.binding.velux.internal.utils.ManifestInformation;
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.i18n.LocaleProvider;
34 import org.openhab.core.i18n.LocationProvider;
35 import org.openhab.core.i18n.TranslationProvider;
36 import org.openhab.core.thing.ThingTypeUID;
37 import org.openhab.core.thing.ThingUID;
38 import org.osgi.service.component.annotations.Component;
39 import org.osgi.service.component.annotations.Reference;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
44 * The {@link VeluxDiscoveryService} is responsible for discovering actuators and scenes on the current Velux Bridge.
46 * @author Guenther Schreiner - Initial contribution.
49 // To-be-discussed: check whether an immediate activation is preferable.
50 // Might be activated by:
51 // @Component(service = DiscoveryService.class, immediate = true, configurationPid = "discovery.velux")
54 @Component(service = DiscoveryService.class, configurationPid = "discovery.velux")
55 public class VeluxDiscoveryService extends AbstractDiscoveryService implements Runnable {
56 private final Logger logger = LoggerFactory.getLogger(VeluxDiscoveryService.class);
60 private static final int DISCOVER_TIMEOUT_SECONDS = 300;
62 private @NonNullByDefault({}) LocaleProvider localeProvider;
63 private @NonNullByDefault({}) TranslationProvider i18nProvider;
64 private Localization localization = Localization.UNKNOWN;
65 private final Set<VeluxBridgeHandler> bridgeHandlers = new HashSet<>();
69 private void updateLocalization() {
70 if (localization == Localization.UNKNOWN && localeProvider != null && i18nProvider != null) {
71 logger.trace("updateLocalization(): creating Localization based on locale={},translation={}).",
72 localeProvider, i18nProvider);
73 localization = new Localization(localeProvider, i18nProvider);
80 * Initializes the {@link VeluxDiscoveryService} without any further information.
82 public VeluxDiscoveryService() {
83 super(VeluxBindingConstants.SUPPORTED_THINGS_ITEMS, DISCOVER_TIMEOUT_SECONDS);
84 logger.trace("VeluxDiscoveryService(without Bridge) just initialized.");
88 protected void setLocaleProvider(final LocaleProvider givenLocaleProvider) {
89 logger.trace("setLocaleProvider(): provided locale={}.", givenLocaleProvider);
90 localeProvider = givenLocaleProvider;
95 protected void setTranslationProvider(TranslationProvider givenI18nProvider) {
96 logger.trace("setTranslationProvider(): provided translation={}.", givenI18nProvider);
97 i18nProvider = givenI18nProvider;
104 * Initializes the {@link VeluxDiscoveryService} with a reference to the well-prepared environment with a
105 * {@link VeluxBridgeHandler}.
107 * @param localizationHandler Initialized localization handler.
109 public VeluxDiscoveryService(Localization localizationHandler) {
110 super(VeluxBindingConstants.SUPPORTED_THINGS_ITEMS, DISCOVER_TIMEOUT_SECONDS);
111 logger.trace("VeluxDiscoveryService(locale={},i18n={}) just initialized.", localeProvider, i18nProvider);
112 localization = localizationHandler;
118 * Initializes the {@link VeluxDiscoveryService} with a reference to the well-prepared environment with a
119 * {@link VeluxBridgeHandler}.
121 * @param locationProvider Provider for a location.
122 * @param localeProvider Provider for a locale.
123 * @param i18nProvider Provider for the internationalization.
125 public VeluxDiscoveryService(LocationProvider locationProvider, LocaleProvider localeProvider,
126 TranslationProvider i18nProvider) {
127 this(new Localization(localeProvider, i18nProvider));
128 logger.trace("VeluxDiscoveryService(locale={},i18n={}) finished.", localeProvider, i18nProvider);
132 public void deactivate() {
133 logger.trace("deactivate() called.");
138 protected synchronized void startScan() {
139 logger.trace("startScan() called.");
141 logger.debug("startScan(): creating a thing of type binding.");
142 ThingUID thingUID = new ThingUID(THING_TYPE_BINDING, "org_openhab_binding_velux");
143 DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID)
144 .withProperty(VeluxBindingProperties.PROPERTY_BINDING_BUNDLEVERSION,
145 ManifestInformation.getBundleVersion())
146 .withLabel(localization.getText("discovery.velux.binding...label")).build();
147 logger.debug("startScan(): registering new thing {}.", discoveryResult);
148 thingDiscovered(discoveryResult);
150 if (bridgeHandlers.isEmpty()) {
151 logger.debug("startScan(): VeluxDiscoveryService cannot proceed due to missing Velux bridge(s).");
153 logger.debug("startScan(): Starting Velux discovery scan for scenes and actuators.");
157 logger.trace("startScan() done.");
161 public synchronized void stopScan() {
162 logger.trace("stopScan() called.");
164 removeOlderResults(getTimestampOfLastScan());
165 logger.trace("stopScan() done.");
170 logger.trace("run() called.");
174 * Discover the gateway-defined scenes.
176 private void discoverScenes() {
177 logger.trace("discoverScenes() called.");
178 for (VeluxBridgeHandler bridgeHandlerX : bridgeHandlers) {
179 ThingUID bridgeUID = bridgeHandlerX.getThing().getUID();
180 logger.debug("discoverScenes(): discovering all scenes on bridge {}.", bridgeUID);
181 for (VeluxScene scene : bridgeHandlerX.existingScenes().values()) {
182 String sceneName = scene.getName().toString();
183 logger.trace("discoverScenes(): found scene {}.", sceneName);
185 String label = sceneName.replaceAll("\\P{Alnum}", "_");
186 logger.trace("discoverScenes(): using label {}.", label);
188 ThingTypeUID thingTypeUID = THING_TYPE_VELUX_SCENE;
189 ThingUID thingUID = new ThingUID(thingTypeUID, bridgeUID, label);
190 DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withThingType(thingTypeUID)
191 .withProperty(VeluxBindingProperties.PROPERTY_SCENE_NAME, sceneName)
192 .withRepresentationProperty(VeluxBindingProperties.PROPERTY_SCENE_NAME).withBridge(bridgeUID)
193 .withLabel(label).build();
194 logger.debug("discoverScenes(): registering new thing {}.", discoveryResult);
195 thingDiscovered(discoveryResult);
198 logger.trace("discoverScenes() finished.");
202 * Discover the gateway-defined products/actuators.
204 private void discoverProducts() {
205 logger.trace("discoverProducts() called.");
206 for (VeluxBridgeHandler bridgeHandlerX : bridgeHandlers) {
207 ThingUID bridgeUID = bridgeHandlerX.getThing().getUID();
208 logger.debug("discoverProducts(): discovering all actuators on bridge {}.", bridgeUID);
209 for (VeluxProduct product : bridgeHandlerX.existingProducts().values()) {
210 String serialNumber = product.getSerialNumber();
211 String actuatorName = product.getProductName().toString();
212 logger.trace("discoverProducts() found actuator {} (name {}).", serialNumber, actuatorName);
214 if (serialNumber.equals(VeluxProductSerialNo.UNKNOWN)) {
215 identifier = actuatorName;
217 identifier = serialNumber;
219 String label = actuatorName.replaceAll("\\P{Alnum}", "_");
220 logger.trace("discoverProducts(): using label {}.", label);
221 ThingTypeUID thingTypeUID;
222 boolean isInverted = false;
223 logger.trace("discoverProducts() dealing with {} (type {}).", product, product.getProductType());
224 switch (product.getProductType()) {
226 logger.trace("discoverProducts(): creating window.");
227 thingTypeUID = THING_TYPE_VELUX_WINDOW;
232 logger.trace("discoverProducts(): creating rollershutter.");
233 thingTypeUID = THING_TYPE_VELUX_ROLLERSHUTTER;
237 logger.trace("discoverProducts(): creating actuator.");
238 thingTypeUID = THING_TYPE_VELUX_ACTUATOR;
240 ThingUID thingUID = new ThingUID(thingTypeUID, bridgeUID, label);
242 DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withThingType(thingTypeUID)
243 .withProperty(VeluxBindingProperties.CONFIG_ACTUATOR_SERIALNUMBER, identifier)
244 .withProperty(VeluxBindingProperties.PROPERTY_ACTUATOR_NAME, actuatorName)
245 .withProperty(VeluxBindingProperties.PROPERTY_ACTUATOR_INVERTED, isInverted)
246 .withRepresentationProperty(VeluxBindingProperties.CONFIG_ACTUATOR_SERIALNUMBER)
247 .withBridge(bridgeUID).withLabel(actuatorName).build();
248 logger.debug("discoverProducts(): registering new thing {}.", discoveryResult);
249 thingDiscovered(discoveryResult);
252 logger.trace("discoverProducts() finished.");
256 * Add a {@link VeluxBridgeHandler} to the {@link VeluxDiscoveryService}
258 * @param bridge Velux bridge handler.
259 * @return true if the bridge was added, or false if it was already present
261 public boolean addBridge(VeluxBridgeHandler bridge) {
262 if (!bridgeHandlers.contains(bridge)) {
263 logger.trace("VeluxDiscoveryService(): registering bridge {} for discovery.", bridge);
264 bridgeHandlers.add(bridge);
267 logger.trace("VeluxDiscoveryService(): bridge {} already registered for discovery.", bridge);
272 * Remove a {@link VeluxBridgeHandler} from the {@link VeluxDiscoveryService}
274 * @param bridge Velux bridge handler.
275 * @return true if the bridge was removed, or false if it was not present
277 public boolean removeBridge(VeluxBridgeHandler bridge) {
278 return bridgeHandlers.remove(bridge);
282 * Check if the {@link VeluxDiscoveryService} list of {@link VeluxBridgeHandler} is empty
284 * @return true if empty
286 public boolean isEmpty() {
287 return bridgeHandlers.isEmpty();