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.weatherunderground.internal.discovery;
15 import static org.openhab.binding.weatherunderground.internal.WeatherUndergroundBindingConstants.*;
16 import static org.openhab.binding.weatherunderground.internal.config.WeatherUndergroundConfiguration.*;
18 import java.util.Collections;
19 import java.util.HashMap;
20 import java.util.Locale;
22 import java.util.Objects;
24 import java.util.concurrent.ScheduledFuture;
25 import java.util.concurrent.TimeUnit;
27 import org.eclipse.jdt.annotation.NonNull;
28 import org.eclipse.jdt.annotation.Nullable;
29 import org.openhab.binding.weatherunderground.internal.handler.WeatherUndergroundHandler;
30 import org.openhab.core.config.discovery.AbstractDiscoveryService;
31 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
32 import org.openhab.core.i18n.LocaleProvider;
33 import org.openhab.core.i18n.LocationProvider;
34 import org.openhab.core.library.types.PointType;
35 import org.openhab.core.thing.ThingTypeUID;
36 import org.openhab.core.thing.ThingUID;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
41 * The {@link WeatherUndergroundDiscoveryService} creates things based on the configured location.
43 * @author Laurent Garnier - Initial Contribution
44 * @author Laurent Garnier - Consider locale (language) when discovering a new thing
46 public class WeatherUndergroundDiscoveryService extends AbstractDiscoveryService {
48 private final Logger logger = LoggerFactory.getLogger(WeatherUndergroundDiscoveryService.class);
49 private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_WEATHER);
50 private static final int DISCOVER_TIMEOUT_SECONDS = 2;
51 private static final int LOCATION_CHANGED_CHECK_INTERVAL = 60;
53 private final LocaleProvider localeProvider;
54 private final LocationProvider locationProvider;
55 private ScheduledFuture<?> discoveryJob;
56 private PointType previousLocation;
57 private String previousLanguage;
58 private String previousCountry;
60 private final ThingUID bridgeUID;
63 * Creates a WeatherUndergroundDiscoveryService with enabled autostart.
66 public WeatherUndergroundDiscoveryService(ThingUID bridgeUID, LocaleProvider localeProvider,
67 LocationProvider locationProvider) {
68 super(SUPPORTED_THING_TYPES, DISCOVER_TIMEOUT_SECONDS, true);
69 this.bridgeUID = bridgeUID;
70 this.localeProvider = localeProvider;
71 this.locationProvider = locationProvider;
74 /* We override this method to allow a call from the thing handler factory */
76 public void activate(@Nullable Map<@NonNull String, @Nullable Object> configProperties) {
77 super.activate(configProperties);
80 /* We override this method to allow a call from the thing handler factory */
82 public void deactivate() {
87 protected void startScan() {
88 logger.debug("Starting Weather Underground discovery scan");
89 PointType location = locationProvider.getLocation();
90 if (location == null) {
91 logger.debug("LocationProvider.getLocation() is not set -> Will not provide any discovery results");
94 createResults(location, localeProvider.getLocale());
98 protected void startBackgroundDiscovery() {
99 logger.debug("Starting Weather Underground device background discovery");
100 if (discoveryJob == null || discoveryJob.isCancelled()) {
101 discoveryJob = scheduler.scheduleWithFixedDelay(() -> {
102 PointType currentLocation = locationProvider.getLocation();
103 String currentLanguage = localeProvider.getLocale().getLanguage();
104 String currentCountry = localeProvider.getLocale().getCountry();
105 if (currentLocation != null) {
106 boolean update = false;
107 if (!Objects.equals(currentLocation, previousLocation)) {
108 logger.debug("Location has been changed from {} to {}: Creating new discovery result",
109 previousLocation, currentLocation);
111 } else if (!Objects.equals(currentLanguage, previousLanguage)) {
112 logger.debug("Language has been changed from {} to {}: Creating new discovery result",
113 previousLanguage, currentLanguage);
115 } else if (!Objects.equals(currentCountry, previousCountry)) {
116 logger.debug("Country has been changed from {} to {}: Creating new discovery result",
117 previousCountry, currentCountry);
121 createResults(currentLocation, localeProvider.getLocale());
122 previousLocation = currentLocation;
123 previousLanguage = currentLanguage;
124 previousCountry = currentCountry;
127 }, 0, LOCATION_CHANGED_CHECK_INTERVAL, TimeUnit.SECONDS);
128 logger.debug("Scheduled Weather Underground location-changed job every {} seconds",
129 LOCATION_CHANGED_CHECK_INTERVAL);
134 protected void stopBackgroundDiscovery() {
135 logger.debug("Stopping Weather Underground device background discovery");
136 if (discoveryJob != null && !discoveryJob.isCancelled()) {
137 discoveryJob.cancel(true);
139 logger.debug("Stopped Weather Underground device background discovery");
143 private void createResults(PointType location, Locale locale) {
144 ThingUID localWeatherThing = new ThingUID(THING_TYPE_WEATHER, bridgeUID, LOCAL);
145 Map<String, Object> properties = new HashMap<>(3);
146 properties.put(LOCATION, String.format("%s,%s", location.getLatitude(), location.getLongitude()));
147 String lang = WeatherUndergroundHandler.getCodeFromLanguage(locale);
148 if (!lang.isEmpty()) {
149 properties.put(LANGUAGE, lang);
151 thingDiscovered(DiscoveryResultBuilder.create(localWeatherThing).withLabel("Local Weather")
152 .withProperties(properties).withBridge(bridgeUID).build());