added migrated 2.x add-ons
Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.openweathermap-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
|
||||
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
|
||||
|
||||
<feature name="openhab-binding-openweathermap" description="OpenWeatherMap Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.openweathermap/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
||||
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.openweathermap.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.type.ChannelGroupTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link OpenWeatherMapBindingConstants} class defines common constants, which are used across the whole binding.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OpenWeatherMapBindingConstants {
|
||||
|
||||
public static final String BINDING_ID = "openweathermap";
|
||||
|
||||
public static final String API = "api";
|
||||
public static final String LOCAL = "local";
|
||||
|
||||
// Bridge
|
||||
public static final ThingTypeUID THING_TYPE_WEATHER_API = new ThingTypeUID(BINDING_ID, "weather-api");
|
||||
|
||||
// Thing
|
||||
public static final ThingTypeUID THING_TYPE_WEATHER_AND_FORECAST = new ThingTypeUID(BINDING_ID,
|
||||
"weather-and-forecast");
|
||||
public static final ThingTypeUID THING_TYPE_UVINDEX = new ThingTypeUID(BINDING_ID, "uvindex");
|
||||
|
||||
// List of all properties
|
||||
public static final String CONFIG_API_KEY = "apikey";
|
||||
public static final String CONFIG_LANGUAGE = "language";
|
||||
public static final String CONFIG_LOCATION = "location";
|
||||
|
||||
// Channel group types
|
||||
public static final ChannelGroupTypeUID CHANNEL_GROUP_TYPE_STATION = new ChannelGroupTypeUID(BINDING_ID, "station");
|
||||
public static final ChannelGroupTypeUID CHANNEL_GROUP_TYPE_HOURLY_FORECAST = new ChannelGroupTypeUID(BINDING_ID,
|
||||
"hourlyForecast");
|
||||
public static final ChannelGroupTypeUID CHANNEL_GROUP_TYPE_DAILY_FORECAST = new ChannelGroupTypeUID(BINDING_ID,
|
||||
"dailyForecast");
|
||||
public static final ChannelGroupTypeUID CHANNEL_GROUP_TYPE_UVINDEX = new ChannelGroupTypeUID(BINDING_ID, "uvindex");
|
||||
|
||||
// List of all channel groups
|
||||
public static final String CHANNEL_GROUP_STATION = "station";
|
||||
public static final String CHANNEL_GROUP_CURRENT_WEATHER = "current";
|
||||
public static final String CHANNEL_GROUP_FORECAST_TODAY = "forecastToday";
|
||||
public static final String CHANNEL_GROUP_FORECAST_TOMORROW = "forecastTomorrow";
|
||||
public static final String CHANNEL_GROUP_CURRENT_UVINDEX = "current";
|
||||
|
||||
// List of all channels
|
||||
public static final String CHANNEL_STATION_ID = "id";
|
||||
public static final String CHANNEL_STATION_NAME = "name";
|
||||
public static final String CHANNEL_STATION_LOCATION = "location";
|
||||
public static final String CHANNEL_TIME_STAMP = "time-stamp";
|
||||
public static final String CHANNEL_CONDITION = "condition";
|
||||
public static final String CHANNEL_CONDITION_ID = "condition-id";
|
||||
public static final String CHANNEL_CONDITION_ICON = "icon";
|
||||
public static final String CHANNEL_CONDITION_ICON_ID = "icon-id";
|
||||
public static final String CHANNEL_TEMPERATURE = "temperature";
|
||||
public static final String CHANNEL_APPARENT_TEMPERATURE = "apparent-temperature";
|
||||
public static final String CHANNEL_MIN_TEMPERATURE = "min-temperature";
|
||||
public static final String CHANNEL_MAX_TEMPERATURE = "max-temperature";
|
||||
public static final String CHANNEL_PRESSURE = "pressure";
|
||||
public static final String CHANNEL_HUMIDITY = "humidity";
|
||||
public static final String CHANNEL_WIND_SPEED = "wind-speed";
|
||||
public static final String CHANNEL_WIND_DIRECTION = "wind-direction";
|
||||
public static final String CHANNEL_GUST_SPEED = "gust-speed";
|
||||
public static final String CHANNEL_CLOUDINESS = "cloudiness";
|
||||
public static final String CHANNEL_RAIN = "rain";
|
||||
public static final String CHANNEL_SNOW = "snow";
|
||||
public static final String CHANNEL_VISIBILITY = "visibility";
|
||||
public static final String CHANNEL_UVINDEX = "uvindex";
|
||||
|
||||
// List of all configuration
|
||||
public static final String CONFIG_FORECAST_DAYS = "forecastDays";
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.openweathermap.internal.config;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.openweathermap.internal.handler.OpenWeatherMapAPIHandler;
|
||||
|
||||
/**
|
||||
* The {@link OpenWeatherMapAPIConfiguration} is the class used to match the {@link OpenWeatherMapAPIHandler}s
|
||||
* configuration.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OpenWeatherMapAPIConfiguration {
|
||||
// supported languages (see https://openweathermap.org/current#multi)
|
||||
public static final Set<String> SUPPORTED_LANGUAGES = Collections.unmodifiableSet(Stream.of("ar", "bg", "ca", "cz",
|
||||
"de", "el", "en", "es", "fa", "fi", "fr", "gl", "hr", "hu", "it", "ja", "kr", "la", "lt", "mk", "nl", "pl",
|
||||
"pt", "ro", "ru", "se", "sk", "sl", "tr", "ua", "vi", "zh_cn", "zh_tw").collect(Collectors.toSet()));
|
||||
|
||||
public @Nullable String apikey;
|
||||
public int refreshInterval;
|
||||
public @Nullable String language;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.openweathermap.internal.config;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.openweathermap.internal.handler.AbstractOpenWeatherMapHandler;
|
||||
|
||||
/**
|
||||
* The {@link OpenWeatherMapLocationConfiguration} is the class used to match the {@link AbstractOpenWeatherMapHandler}s
|
||||
* configuration.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OpenWeatherMapLocationConfiguration {
|
||||
public @NonNullByDefault({}) String location;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.openweathermap.internal.config;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.openweathermap.internal.handler.OpenWeatherMapUVIndexHandler;
|
||||
|
||||
/**
|
||||
* The {@link OpenWeatherMapUVIndexConfiguration} is the class used to match the
|
||||
* {@link OpenWeatherMapUVIndexHandler}s configuration.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OpenWeatherMapUVIndexConfiguration extends OpenWeatherMapLocationConfiguration {
|
||||
public int forecastDays;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.openweathermap.internal.config;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.openweathermap.internal.handler.OpenWeatherMapWeatherAndForecastHandler;
|
||||
|
||||
/**
|
||||
* The {@link OpenWeatherMapWeatherAndForecastConfiguration} is the class used to match the
|
||||
* {@link OpenWeatherMapWeatherAndForecastHandler}s configuration.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OpenWeatherMapWeatherAndForecastConfiguration extends OpenWeatherMapLocationConfiguration {
|
||||
public int forecastHours;
|
||||
public int forecastDays;
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.openweathermap.internal.connection;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link OpenWeatherMapCommunicationException} is a communication exception for the connections to OpenWeatherMap
|
||||
* API.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OpenWeatherMapCommunicationException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Constructs a new exception with null as its detail message.
|
||||
*/
|
||||
public OpenWeatherMapCommunicationException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new exception with the specified detail message.
|
||||
*
|
||||
* @param message Detail message
|
||||
*/
|
||||
public OpenWeatherMapCommunicationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new exception with the specified cause.
|
||||
*
|
||||
* @param cause The cause
|
||||
*/
|
||||
public OpenWeatherMapCommunicationException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new exception with the specified detail message and cause.
|
||||
*
|
||||
* @param message Detail message
|
||||
* @param cause The cause
|
||||
*/
|
||||
public OpenWeatherMapCommunicationException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.openweathermap.internal.connection;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link OpenWeatherMapConfigurationException} is a configuration exception for the connections to OpenWeatherMap
|
||||
* API.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OpenWeatherMapConfigurationException extends IllegalArgumentException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Constructs a new exception with null as its detail message.
|
||||
*/
|
||||
public OpenWeatherMapConfigurationException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new exception with the specified detail message.
|
||||
*
|
||||
* @param message Detail message
|
||||
*/
|
||||
public OpenWeatherMapConfigurationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new exception with the specified cause.
|
||||
*
|
||||
* @param cause The cause
|
||||
*/
|
||||
public OpenWeatherMapConfigurationException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new exception with the specified detail message and cause.
|
||||
*
|
||||
* @param message Detail message
|
||||
* @param cause The cause
|
||||
*/
|
||||
public OpenWeatherMapConfigurationException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,344 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.openweathermap.internal.connection;
|
||||
|
||||
import static java.util.stream.Collectors.joining;
|
||||
import static org.eclipse.jetty.http.HttpMethod.GET;
|
||||
import static org.eclipse.jetty.http.HttpStatus.*;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.HttpResponseException;
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.openhab.binding.openweathermap.internal.config.OpenWeatherMapAPIConfiguration;
|
||||
import org.openhab.binding.openweathermap.internal.dto.OpenWeatherMapJsonDailyForecastData;
|
||||
import org.openhab.binding.openweathermap.internal.dto.OpenWeatherMapJsonHourlyForecastData;
|
||||
import org.openhab.binding.openweathermap.internal.dto.OpenWeatherMapJsonUVIndexData;
|
||||
import org.openhab.binding.openweathermap.internal.dto.OpenWeatherMapJsonWeatherData;
|
||||
import org.openhab.binding.openweathermap.internal.handler.OpenWeatherMapAPIHandler;
|
||||
import org.openhab.binding.openweathermap.internal.utils.ByteArrayFileCache;
|
||||
import org.openhab.core.cache.ExpiringCacheMap;
|
||||
import org.openhab.core.io.net.http.HttpUtil;
|
||||
import org.openhab.core.library.types.PointType;
|
||||
import org.openhab.core.library.types.RawType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
/**
|
||||
* The {@link OpenWeatherMapConnection} is responsible for handling the connections to OpenWeatherMap API.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OpenWeatherMapConnection {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(OpenWeatherMapConnection.class);
|
||||
|
||||
private static final String PROPERTY_MESSAGE = "message";
|
||||
|
||||
private static final String PNG_CONTENT_TYPE = "image/png";
|
||||
|
||||
private static final String PARAM_APPID = "appid";
|
||||
private static final String PARAM_UNITS = "units";
|
||||
private static final String PARAM_LAT = "lat";
|
||||
private static final String PARAM_LON = "lon";
|
||||
private static final String PARAM_LANG = "lang";
|
||||
private static final String PARAM_FORECAST_CNT = "cnt";
|
||||
|
||||
// Current weather data (see https://openweathermap.org/current)
|
||||
private static final String WEATHER_URL = "https://api.openweathermap.org/data/2.5/weather";
|
||||
// 5 day / 3 hour forecast (see https://openweathermap.org/forecast5)
|
||||
private static final String THREE_HOUR_FORECAST_URL = "https://api.openweathermap.org/data/2.5/forecast";
|
||||
// 16 day / daily forecast (see https://openweathermap.org/forecast16)
|
||||
private static final String DAILY_FORECAST_URL = "https://api.openweathermap.org/data/2.5/forecast/daily";
|
||||
// UV Index (see https://openweathermap.org/api/uvi)
|
||||
private static final String UVINDEX_URL = "https://api.openweathermap.org/data/2.5/uvi";
|
||||
private static final String UVINDEX_FORECAST_URL = "https://api.openweathermap.org/data/2.5/uvi/forecast";
|
||||
// Weather icons (see https://openweathermap.org/weather-conditions)
|
||||
private static final String ICON_URL = "https://openweathermap.org/img/w/%s.png";
|
||||
|
||||
private final OpenWeatherMapAPIHandler handler;
|
||||
private final HttpClient httpClient;
|
||||
|
||||
private static final ByteArrayFileCache IMAGE_CACHE = new ByteArrayFileCache("org.openhab.binding.openweathermap");
|
||||
private final ExpiringCacheMap<String, String> cache;
|
||||
|
||||
private final JsonParser parser = new JsonParser();
|
||||
private final Gson gson = new Gson();
|
||||
|
||||
public OpenWeatherMapConnection(OpenWeatherMapAPIHandler handler, HttpClient httpClient) {
|
||||
this.handler = handler;
|
||||
this.httpClient = httpClient;
|
||||
|
||||
OpenWeatherMapAPIConfiguration config = handler.getOpenWeatherMapAPIConfig();
|
||||
cache = new ExpiringCacheMap<>(TimeUnit.MINUTES.toMillis(config.refreshInterval));
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests the current weather data for the given location (see https://openweathermap.org/current).
|
||||
*
|
||||
* @param location location represented as {@link PointType}
|
||||
* @return the current weather data
|
||||
* @throws JsonSyntaxException
|
||||
* @throws OpenWeatherMapCommunicationException
|
||||
* @throws OpenWeatherMapConfigurationException
|
||||
*/
|
||||
public synchronized @Nullable OpenWeatherMapJsonWeatherData getWeatherData(@Nullable PointType location)
|
||||
throws JsonSyntaxException, OpenWeatherMapCommunicationException, OpenWeatherMapConfigurationException {
|
||||
return gson.fromJson(
|
||||
getResponseFromCache(
|
||||
buildURL(WEATHER_URL, getRequestParams(handler.getOpenWeatherMapAPIConfig(), location))),
|
||||
OpenWeatherMapJsonWeatherData.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests the hourly forecast data for the given location (see https://openweathermap.org/forecast5).
|
||||
*
|
||||
* @param location location represented as {@link PointType}
|
||||
* @param count number of hours
|
||||
* @return the hourly forecast data
|
||||
* @throws JsonSyntaxException
|
||||
* @throws OpenWeatherMapCommunicationException
|
||||
* @throws OpenWeatherMapConfigurationException
|
||||
*/
|
||||
public synchronized @Nullable OpenWeatherMapJsonHourlyForecastData getHourlyForecastData(
|
||||
@Nullable PointType location, int count)
|
||||
throws JsonSyntaxException, OpenWeatherMapCommunicationException, OpenWeatherMapConfigurationException {
|
||||
if (count <= 0) {
|
||||
throw new OpenWeatherMapConfigurationException("@text/offline.conf-error-not-supported-number-of-hours");
|
||||
}
|
||||
|
||||
Map<String, String> params = getRequestParams(handler.getOpenWeatherMapAPIConfig(), location);
|
||||
params.put(PARAM_FORECAST_CNT, Integer.toString(count));
|
||||
|
||||
return gson.fromJson(getResponseFromCache(buildURL(THREE_HOUR_FORECAST_URL, params)),
|
||||
OpenWeatherMapJsonHourlyForecastData.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests the daily forecast data for the given location (see https://openweathermap.org/forecast16).
|
||||
*
|
||||
* @param location location represented as {@link PointType}
|
||||
* @param count number of days
|
||||
* @return the daily forecast data
|
||||
* @throws JsonSyntaxException
|
||||
* @throws OpenWeatherMapCommunicationException
|
||||
* @throws OpenWeatherMapConfigurationException
|
||||
*/
|
||||
public synchronized @Nullable OpenWeatherMapJsonDailyForecastData getDailyForecastData(@Nullable PointType location,
|
||||
int count)
|
||||
throws JsonSyntaxException, OpenWeatherMapCommunicationException, OpenWeatherMapConfigurationException {
|
||||
if (count <= 0) {
|
||||
throw new OpenWeatherMapConfigurationException("@text/offline.conf-error-not-supported-number-of-days");
|
||||
}
|
||||
|
||||
Map<String, String> params = getRequestParams(handler.getOpenWeatherMapAPIConfig(), location);
|
||||
params.put(PARAM_FORECAST_CNT, Integer.toString(count));
|
||||
|
||||
return gson.fromJson(getResponseFromCache(buildURL(DAILY_FORECAST_URL, params)),
|
||||
OpenWeatherMapJsonDailyForecastData.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests the UV Index data for the given location (see https://api.openweathermap.org/data/2.5/uvi).
|
||||
*
|
||||
* @param location location represented as {@link PointType}
|
||||
* @return the UV Index data
|
||||
* @throws JsonSyntaxException
|
||||
* @throws OpenWeatherMapCommunicationException
|
||||
* @throws OpenWeatherMapConfigurationException
|
||||
*/
|
||||
public synchronized @Nullable OpenWeatherMapJsonUVIndexData getUVIndexData(@Nullable PointType location)
|
||||
throws JsonSyntaxException, OpenWeatherMapCommunicationException, OpenWeatherMapConfigurationException {
|
||||
return gson.fromJson(
|
||||
getResponseFromCache(
|
||||
buildURL(UVINDEX_URL, getRequestParams(handler.getOpenWeatherMapAPIConfig(), location))),
|
||||
OpenWeatherMapJsonUVIndexData.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests the UV Index forecast data for the given location (see https://api.openweathermap.org/data/2.5/uvi).
|
||||
*
|
||||
* @param location location represented as {@link PointType}
|
||||
* @return the UV Index forecast data
|
||||
* @throws JsonSyntaxException
|
||||
* @throws OpenWeatherMapCommunicationException
|
||||
* @throws OpenWeatherMapConfigurationException
|
||||
*/
|
||||
public synchronized @Nullable List<OpenWeatherMapJsonUVIndexData> getUVIndexForecastData(
|
||||
@Nullable PointType location, int count)
|
||||
throws JsonSyntaxException, OpenWeatherMapCommunicationException, OpenWeatherMapConfigurationException {
|
||||
if (count <= 0) {
|
||||
throw new OpenWeatherMapConfigurationException(
|
||||
"@text/offline.conf-error-not-supported-uvindex-number-of-days");
|
||||
}
|
||||
|
||||
Map<String, String> params = getRequestParams(handler.getOpenWeatherMapAPIConfig(), location);
|
||||
params.put(PARAM_FORECAST_CNT, Integer.toString(count));
|
||||
|
||||
return Arrays.asList(gson.fromJson(getResponseFromCache(buildURL(UVINDEX_FORECAST_URL, params)),
|
||||
OpenWeatherMapJsonUVIndexData[].class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads the icon for the given icon id (see https://openweathermap.org/weather-conditions).
|
||||
*
|
||||
* @param iconId the id of the icon
|
||||
* @return the weather icon as {@link RawType}
|
||||
*/
|
||||
public static @Nullable RawType getWeatherIcon(String iconId) {
|
||||
if (iconId.isEmpty()) {
|
||||
throw new IllegalArgumentException("Cannot download weather icon as icon id is null.");
|
||||
}
|
||||
|
||||
return downloadWeatherIconFromCache(String.format(ICON_URL, iconId));
|
||||
}
|
||||
|
||||
private static @Nullable RawType downloadWeatherIconFromCache(String url) {
|
||||
if (IMAGE_CACHE.containsKey(url)) {
|
||||
return new RawType(IMAGE_CACHE.get(url), PNG_CONTENT_TYPE);
|
||||
} else {
|
||||
RawType image = downloadWeatherIcon(url);
|
||||
if (image != null) {
|
||||
IMAGE_CACHE.put(url, image.getBytes());
|
||||
return image;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static @Nullable RawType downloadWeatherIcon(String url) {
|
||||
return HttpUtil.downloadImage(url);
|
||||
}
|
||||
|
||||
private Map<String, String> getRequestParams(OpenWeatherMapAPIConfiguration config, @Nullable PointType location) {
|
||||
if (location == null) {
|
||||
throw new OpenWeatherMapConfigurationException("@text/offline.conf-error-missing-location");
|
||||
}
|
||||
|
||||
Map<String, String> params = new HashMap<>();
|
||||
// API key (see http://openweathermap.org/appid)
|
||||
String apikey = config.apikey;
|
||||
if (apikey == null || (apikey = apikey.trim()).isEmpty()) {
|
||||
throw new OpenWeatherMapConfigurationException("@text/offline.conf-error-missing-apikey");
|
||||
}
|
||||
params.put(PARAM_APPID, apikey);
|
||||
|
||||
// Units format (see https://openweathermap.org/current#data)
|
||||
params.put(PARAM_UNITS, "metric");
|
||||
|
||||
// By geographic coordinates (see https://openweathermap.org/current#geo)
|
||||
params.put(PARAM_LAT, location.getLatitude().toString());
|
||||
params.put(PARAM_LON, location.getLongitude().toString());
|
||||
|
||||
// Multilingual support (see https://openweathermap.org/current#multi)
|
||||
String language = config.language;
|
||||
if (language != null && !(language = language.trim()).isEmpty()) {
|
||||
params.put(PARAM_LANG, language.toLowerCase());
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
private String buildURL(String url, Map<String, String> requestParams) {
|
||||
return requestParams.keySet().stream().map(key -> key + "=" + encodeParam(requestParams.get(key)))
|
||||
.collect(joining("&", url + "?", ""));
|
||||
}
|
||||
|
||||
private String encodeParam(String value) {
|
||||
try {
|
||||
return URLEncoder.encode(value, StandardCharsets.UTF_8.name());
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
logger.debug("UnsupportedEncodingException occurred during execution: {}", e.getLocalizedMessage(), e);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private @Nullable String getResponseFromCache(String url) {
|
||||
return cache.putIfAbsentAndGet(url, () -> getResponse(url));
|
||||
}
|
||||
|
||||
private String getResponse(String url) {
|
||||
try {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("OpenWeatherMap request: URL = '{}'", uglifyApikey(url));
|
||||
}
|
||||
ContentResponse contentResponse = httpClient.newRequest(url).method(GET).timeout(10, TimeUnit.SECONDS)
|
||||
.send();
|
||||
int httpStatus = contentResponse.getStatus();
|
||||
String content = contentResponse.getContentAsString();
|
||||
String errorMessage = "";
|
||||
logger.trace("OpenWeatherMap response: status = {}, content = '{}'", httpStatus, content);
|
||||
switch (httpStatus) {
|
||||
case OK_200:
|
||||
return content;
|
||||
case BAD_REQUEST_400:
|
||||
case UNAUTHORIZED_401:
|
||||
case NOT_FOUND_404:
|
||||
errorMessage = getErrorMessage(content);
|
||||
logger.debug("OpenWeatherMap server responded with status code {}: {}", httpStatus, errorMessage);
|
||||
throw new OpenWeatherMapConfigurationException(errorMessage);
|
||||
case TOO_MANY_REQUESTS_429:
|
||||
// TODO disable refresh job temporarily (see https://openweathermap.org/appid#Accesslimitation)
|
||||
default:
|
||||
errorMessage = getErrorMessage(content);
|
||||
logger.debug("OpenWeatherMap server responded with status code {}: {}", httpStatus, errorMessage);
|
||||
throw new OpenWeatherMapCommunicationException(errorMessage);
|
||||
}
|
||||
} catch (ExecutionException e) {
|
||||
String errorMessage = e.getLocalizedMessage();
|
||||
logger.trace("Exception occurred during execution: {}", errorMessage, e);
|
||||
if (e.getCause() instanceof HttpResponseException) {
|
||||
logger.debug("OpenWeatherMap server responded with status code {}: Invalid API key.", UNAUTHORIZED_401);
|
||||
throw new OpenWeatherMapConfigurationException("@text/offline.conf-error-invalid-apikey", e.getCause());
|
||||
} else {
|
||||
throw new OpenWeatherMapCommunicationException(errorMessage, e.getCause());
|
||||
}
|
||||
} catch (InterruptedException | TimeoutException e) {
|
||||
logger.debug("Exception occurred during execution: {}", e.getLocalizedMessage(), e);
|
||||
throw new OpenWeatherMapCommunicationException(e.getLocalizedMessage(), e.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
private String uglifyApikey(String url) {
|
||||
return url.replaceAll("(appid=)+\\w+", "appid=*****");
|
||||
}
|
||||
|
||||
private String getErrorMessage(String response) {
|
||||
JsonElement jsonResponse = parser.parse(response);
|
||||
if (jsonResponse.isJsonObject()) {
|
||||
JsonObject json = jsonResponse.getAsJsonObject();
|
||||
if (json.has(PROPERTY_MESSAGE)) {
|
||||
return json.get(PROPERTY_MESSAGE).getAsString();
|
||||
}
|
||||
}
|
||||
return response;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.openweathermap.internal.discovery;
|
||||
|
||||
import static org.openhab.binding.openweathermap.internal.OpenWeatherMapBindingConstants.*;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.openweathermap.internal.handler.AbstractOpenWeatherMapHandler;
|
||||
import org.openhab.binding.openweathermap.internal.handler.OpenWeatherMapAPIHandler;
|
||||
import org.openhab.core.config.discovery.AbstractDiscoveryService;
|
||||
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
||||
import org.openhab.core.i18n.LocaleProvider;
|
||||
import org.openhab.core.i18n.LocationProvider;
|
||||
import org.openhab.core.i18n.TranslationProvider;
|
||||
import org.openhab.core.library.types.PointType;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link OpenWeatherMapDiscoveryService} creates things based on the configured location.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial Contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OpenWeatherMapDiscoveryService extends AbstractDiscoveryService {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(OpenWeatherMapDiscoveryService.class);
|
||||
|
||||
private static final int DISCOVERY_TIMEOUT_SECONDS = 2;
|
||||
private static final int DISCOVERY_INTERVAL_SECONDS = 60;
|
||||
private @Nullable ScheduledFuture<?> discoveryJob;
|
||||
private final LocationProvider locationProvider;
|
||||
private @Nullable PointType previousLocation;
|
||||
|
||||
private final OpenWeatherMapAPIHandler bridgeHandler;
|
||||
|
||||
/**
|
||||
* Creates an OpenWeatherMapLocationDiscoveryService.
|
||||
*/
|
||||
public OpenWeatherMapDiscoveryService(OpenWeatherMapAPIHandler bridgeHandler, LocationProvider locationProvider,
|
||||
LocaleProvider localeProvider, TranslationProvider i18nProvider) {
|
||||
super(AbstractOpenWeatherMapHandler.SUPPORTED_THING_TYPES, DISCOVERY_TIMEOUT_SECONDS);
|
||||
this.bridgeHandler = bridgeHandler;
|
||||
this.locationProvider = locationProvider;
|
||||
this.localeProvider = localeProvider;
|
||||
this.i18nProvider = i18nProvider;
|
||||
activate(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void activate(@Nullable Map<String, @Nullable Object> configProperties) {
|
||||
super.activate(configProperties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deactivate() {
|
||||
removeOlderResults(new Date().getTime(), bridgeHandler.getThing().getUID());
|
||||
super.deactivate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startScan() {
|
||||
logger.debug("Start manual OpenWeatherMap Location discovery scan.");
|
||||
scanForNewLocation(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void stopScan() {
|
||||
logger.debug("Stop manual OpenWeatherMap Location discovery scan.");
|
||||
super.stopScan();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startBackgroundDiscovery() {
|
||||
if (discoveryJob == null || discoveryJob.isCancelled()) {
|
||||
logger.debug("Start OpenWeatherMap Location background discovery job at interval {} s.",
|
||||
DISCOVERY_INTERVAL_SECONDS);
|
||||
discoveryJob = scheduler.scheduleWithFixedDelay(() -> {
|
||||
scanForNewLocation(true);
|
||||
}, 0, DISCOVERY_INTERVAL_SECONDS, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void stopBackgroundDiscovery() {
|
||||
if (discoveryJob != null && !discoveryJob.isCancelled()) {
|
||||
logger.debug("Stop OpenWeatherMap Location background discovery job.");
|
||||
if (discoveryJob.cancel(true)) {
|
||||
discoveryJob = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void scanForNewLocation(boolean updateOnlyIfNewLocation) {
|
||||
PointType currentLocation = locationProvider.getLocation();
|
||||
if (currentLocation == null) {
|
||||
logger.debug("Location is not set -> Will not provide any discovery results.");
|
||||
} else if (!Objects.equals(currentLocation, previousLocation)) {
|
||||
logger.debug("Location has been changed from {} to {} -> Creating new discovery results.", previousLocation,
|
||||
currentLocation);
|
||||
createResults(currentLocation);
|
||||
previousLocation = currentLocation;
|
||||
} else if (!updateOnlyIfNewLocation) {
|
||||
createResults(currentLocation);
|
||||
}
|
||||
}
|
||||
|
||||
private void createResults(PointType location) {
|
||||
String locationString = location.toFullString();
|
||||
ThingUID bridgeUID = bridgeHandler.getThing().getUID();
|
||||
createWeatherAndForecastResult(locationString, bridgeUID);
|
||||
createUVIndexResult(locationString, bridgeUID);
|
||||
}
|
||||
|
||||
private void createWeatherAndForecastResult(String location, ThingUID bridgeUID) {
|
||||
thingDiscovered(DiscoveryResultBuilder.create(new ThingUID(THING_TYPE_WEATHER_AND_FORECAST, bridgeUID, LOCAL))
|
||||
.withLabel("Local weather and forecast").withProperty(CONFIG_LOCATION, location)
|
||||
.withRepresentationProperty(CONFIG_LOCATION).withBridge(bridgeUID).build());
|
||||
}
|
||||
|
||||
private void createUVIndexResult(String location, ThingUID bridgeUID) {
|
||||
thingDiscovered(DiscoveryResultBuilder.create(new ThingUID(THING_TYPE_UVINDEX, bridgeUID, LOCAL))
|
||||
.withLabel("Local UV Index").withProperty(CONFIG_LOCATION, location)
|
||||
.withRepresentationProperty(CONFIG_LOCATION).withBridge(bridgeUID).build());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.openweathermap.internal.dto;
|
||||
|
||||
import org.openhab.binding.openweathermap.internal.dto.base.City;
|
||||
import org.openhab.binding.openweathermap.internal.dto.forecast.daily.List;
|
||||
|
||||
/**
|
||||
* The {@link OpenWeatherMapJsonDailyForecastData} is the Java class used to map the JSON response to an OpenWeatherMap
|
||||
* request.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
public class OpenWeatherMapJsonDailyForecastData {
|
||||
private City city;
|
||||
private String cod;
|
||||
private Double message;
|
||||
private Integer cnt;
|
||||
private java.util.List<List> list;
|
||||
|
||||
public City getCity() {
|
||||
return city;
|
||||
}
|
||||
|
||||
public void setCity(City city) {
|
||||
this.city = city;
|
||||
}
|
||||
|
||||
public String getCod() {
|
||||
return cod;
|
||||
}
|
||||
|
||||
public void setCod(String cod) {
|
||||
this.cod = cod;
|
||||
}
|
||||
|
||||
public Double getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(Double message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public Integer getCnt() {
|
||||
return cnt;
|
||||
}
|
||||
|
||||
public void setCnt(Integer cnt) {
|
||||
this.cnt = cnt;
|
||||
}
|
||||
|
||||
public java.util.List<List> getList() {
|
||||
return list;
|
||||
}
|
||||
|
||||
public void setList(java.util.List<List> list) {
|
||||
this.list = list;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.openweathermap.internal.dto;
|
||||
|
||||
import org.openhab.binding.openweathermap.internal.dto.base.City;
|
||||
import org.openhab.binding.openweathermap.internal.dto.forecast.hourly.List;
|
||||
|
||||
/**
|
||||
* The {@link OpenWeatherMapJsonHourlyForecastData} is the Java class used to map the JSON response to an OpenWeatherMap
|
||||
* request.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
public class OpenWeatherMapJsonHourlyForecastData {
|
||||
private String cod;
|
||||
private Double message;
|
||||
private Integer cnt;
|
||||
private java.util.List<List> list;
|
||||
private City city;
|
||||
|
||||
public String getCod() {
|
||||
return cod;
|
||||
}
|
||||
|
||||
public void setCod(String cod) {
|
||||
this.cod = cod;
|
||||
}
|
||||
|
||||
public Double getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(Double message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public Integer getCnt() {
|
||||
return cnt;
|
||||
}
|
||||
|
||||
public void setCnt(Integer cnt) {
|
||||
this.cnt = cnt;
|
||||
}
|
||||
|
||||
public java.util.List<List> getList() {
|
||||
return list;
|
||||
}
|
||||
|
||||
public void setList(java.util.List<List> list) {
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
public City getCity() {
|
||||
return city;
|
||||
}
|
||||
|
||||
public void setCity(City city) {
|
||||
this.city = city;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.openweathermap.internal.dto;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link OpenWeatherMapJsonUVIndexData} is the Java class used to map the JSON response to an OpenWeatherMap
|
||||
* request.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
public class OpenWeatherMapJsonUVIndexData {
|
||||
private Double lat;
|
||||
private Double lon;
|
||||
@SerializedName("date_iso")
|
||||
private String dateIso;
|
||||
private Integer date;
|
||||
private Double value;
|
||||
|
||||
public Double getLat() {
|
||||
return lat;
|
||||
}
|
||||
|
||||
public void setLat(Double lat) {
|
||||
this.lat = lat;
|
||||
}
|
||||
|
||||
public Double getLon() {
|
||||
return lon;
|
||||
}
|
||||
|
||||
public void setLon(Double lon) {
|
||||
this.lon = lon;
|
||||
}
|
||||
|
||||
public String getDateIso() {
|
||||
return dateIso;
|
||||
}
|
||||
|
||||
public void setDateIso(String dateIso) {
|
||||
this.dateIso = dateIso;
|
||||
}
|
||||
|
||||
public Integer getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public void setDate(Integer date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public Double getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(Double value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.openweathermap.internal.dto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.openweathermap.internal.dto.base.Clouds;
|
||||
import org.openhab.binding.openweathermap.internal.dto.base.Coord;
|
||||
import org.openhab.binding.openweathermap.internal.dto.base.Rain;
|
||||
import org.openhab.binding.openweathermap.internal.dto.base.Snow;
|
||||
import org.openhab.binding.openweathermap.internal.dto.base.Weather;
|
||||
import org.openhab.binding.openweathermap.internal.dto.base.Wind;
|
||||
import org.openhab.binding.openweathermap.internal.dto.weather.Main;
|
||||
import org.openhab.binding.openweathermap.internal.dto.weather.Sys;
|
||||
|
||||
/**
|
||||
* The {@link OpenWeatherMapJsonWeatherData} is the Java class used to map the JSON response to an OpenWeatherMap
|
||||
* request.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
public class OpenWeatherMapJsonWeatherData {
|
||||
private Coord coord;
|
||||
private List<Weather> weather;
|
||||
private String base;
|
||||
private Main main;
|
||||
private @Nullable Integer visibility;
|
||||
private Wind wind;
|
||||
private Clouds clouds;
|
||||
private @Nullable Rain rain;
|
||||
private @Nullable Snow snow;
|
||||
private Integer dt;
|
||||
private Sys sys;
|
||||
private Integer id;
|
||||
private String name;
|
||||
private Integer cod;
|
||||
|
||||
public Coord getCoord() {
|
||||
return coord;
|
||||
}
|
||||
|
||||
public void setCoord(Coord coord) {
|
||||
this.coord = coord;
|
||||
}
|
||||
|
||||
public List<Weather> getWeather() {
|
||||
return weather;
|
||||
}
|
||||
|
||||
public void setWeather(List<Weather> weather) {
|
||||
this.weather = weather;
|
||||
}
|
||||
|
||||
public String getBase() {
|
||||
return base;
|
||||
}
|
||||
|
||||
public void setBase(String base) {
|
||||
this.base = base;
|
||||
}
|
||||
|
||||
public Main getMain() {
|
||||
return main;
|
||||
}
|
||||
|
||||
public void setMain(Main main) {
|
||||
this.main = main;
|
||||
}
|
||||
|
||||
public @Nullable Integer getVisibility() {
|
||||
return visibility;
|
||||
}
|
||||
|
||||
public void setVisibility(Integer visibility) {
|
||||
this.visibility = visibility;
|
||||
}
|
||||
|
||||
public Wind getWind() {
|
||||
return wind;
|
||||
}
|
||||
|
||||
public void setWind(Wind wind) {
|
||||
this.wind = wind;
|
||||
}
|
||||
|
||||
public Clouds getClouds() {
|
||||
return clouds;
|
||||
}
|
||||
|
||||
public void setClouds(Clouds clouds) {
|
||||
this.clouds = clouds;
|
||||
}
|
||||
|
||||
public @Nullable Rain getRain() {
|
||||
return rain;
|
||||
}
|
||||
|
||||
public void setRain(Rain rain) {
|
||||
this.rain = rain;
|
||||
}
|
||||
|
||||
public @Nullable Snow getSnow() {
|
||||
return snow;
|
||||
}
|
||||
|
||||
public void setSnow(Snow snow) {
|
||||
this.snow = snow;
|
||||
}
|
||||
|
||||
public Integer getDt() {
|
||||
return dt;
|
||||
}
|
||||
|
||||
public void setDt(Integer dt) {
|
||||
this.dt = dt;
|
||||
}
|
||||
|
||||
public Sys getSys() {
|
||||
return sys;
|
||||
}
|
||||
|
||||
public void setSys(Sys sys) {
|
||||
this.sys = sys;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getCod() {
|
||||
return cod;
|
||||
}
|
||||
|
||||
public void setCod(Integer cod) {
|
||||
this.cod = cod;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.openweathermap.internal.dto.base;
|
||||
|
||||
/**
|
||||
* Generated Plain Old Java Objects class for {@link City} from JSON.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
public class City {
|
||||
private Integer id;
|
||||
private Coord coord;
|
||||
private String country;
|
||||
private Integer population;
|
||||
private String name;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Coord getCoord() {
|
||||
return coord;
|
||||
}
|
||||
|
||||
public void setCoord(Coord coord) {
|
||||
this.coord = coord;
|
||||
}
|
||||
|
||||
public String getCountry() {
|
||||
return country;
|
||||
}
|
||||
|
||||
public void setCountry(String country) {
|
||||
this.country = country;
|
||||
}
|
||||
|
||||
public Integer getPopulation() {
|
||||
return population;
|
||||
}
|
||||
|
||||
public void setPopulation(Integer population) {
|
||||
this.population = population;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.openweathermap.internal.dto.base;
|
||||
|
||||
/**
|
||||
* Generated Plain Old Java Objects class for {@link Clouds} from JSON.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
public class Clouds {
|
||||
private Integer all;
|
||||
|
||||
public Integer getAll() {
|
||||
return all;
|
||||
}
|
||||
|
||||
public void setAll(Integer all) {
|
||||
this.all = all;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.openweathermap.internal.dto.base;
|
||||
|
||||
/**
|
||||
* Generated Plain Old Java Objects class for {@link Coord} from JSON.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
public class Coord {
|
||||
private Double lon;
|
||||
private Double lat;
|
||||
|
||||
public Double getLon() {
|
||||
return lon;
|
||||
}
|
||||
|
||||
public void setLon(Double lon) {
|
||||
this.lon = lon;
|
||||
}
|
||||
|
||||
public Double getLat() {
|
||||
return lat;
|
||||
}
|
||||
|
||||
public void setLat(Double lat) {
|
||||
this.lat = lat;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.openweathermap.internal.dto.base;
|
||||
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* Generated Plain Old Java Objects class for {@link Rain} from JSON.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
public class Rain {
|
||||
@SerializedName("1h")
|
||||
private @Nullable Double oneHour;
|
||||
@SerializedName("3h")
|
||||
private @Nullable Double threeHours;
|
||||
|
||||
public @Nullable Double get1h() {
|
||||
return oneHour;
|
||||
}
|
||||
|
||||
public void set1h(Double oneHour) {
|
||||
this.oneHour = oneHour;
|
||||
}
|
||||
|
||||
public @Nullable Double get3h() {
|
||||
return threeHours;
|
||||
}
|
||||
|
||||
public void set3h(Double threeHours) {
|
||||
this.threeHours = threeHours;
|
||||
}
|
||||
|
||||
public Double getVolume() {
|
||||
return oneHour != null ? oneHour : threeHours != null ? threeHours / 3 : 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.openweathermap.internal.dto.base;
|
||||
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* Generated Plain Old Java Objects class for {@link Snow} from JSON.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
public class Snow {
|
||||
@SerializedName("1h")
|
||||
private @Nullable Double oneHour;
|
||||
@SerializedName("3h")
|
||||
private @Nullable Double threeHours;
|
||||
|
||||
public @Nullable Double get1h() {
|
||||
return oneHour;
|
||||
}
|
||||
|
||||
public void set1h(Double oneHour) {
|
||||
this.oneHour = oneHour;
|
||||
}
|
||||
|
||||
public @Nullable Double get3h() {
|
||||
return threeHours;
|
||||
}
|
||||
|
||||
public void set3h(Double threeHours) {
|
||||
this.threeHours = threeHours;
|
||||
}
|
||||
|
||||
public Double getVolume() {
|
||||
return oneHour != null ? oneHour : threeHours != null ? threeHours / 3 : 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.openweathermap.internal.dto.base;
|
||||
|
||||
/**
|
||||
* Generates Plain Old Java Objects class for {@link Weather} from JSON.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
public class Weather {
|
||||
private Integer id;
|
||||
private String main;
|
||||
private String description;
|
||||
private String icon;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getMain() {
|
||||
return main;
|
||||
}
|
||||
|
||||
public void setMain(String main) {
|
||||
this.main = main;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getIcon() {
|
||||
return icon;
|
||||
}
|
||||
|
||||
public void setIcon(String icon) {
|
||||
this.icon = icon;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.openweathermap.internal.dto.base;
|
||||
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Generated Plain Old Java Objects class for {@link Wind} from JSON.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
public class Wind {
|
||||
private Double speed;
|
||||
private Double deg;
|
||||
private @Nullable Double gust;
|
||||
|
||||
public Double getSpeed() {
|
||||
return speed;
|
||||
}
|
||||
|
||||
public void setSpeed(Double speed) {
|
||||
this.speed = speed;
|
||||
}
|
||||
|
||||
public Double getDeg() {
|
||||
return deg;
|
||||
}
|
||||
|
||||
public void setDeg(Double deg) {
|
||||
this.deg = deg;
|
||||
}
|
||||
|
||||
public @Nullable Double getGust() {
|
||||
return gust;
|
||||
}
|
||||
|
||||
public void setGust(Double gust) {
|
||||
this.gust = speed;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.openweathermap.internal.dto.forecast.daily;
|
||||
|
||||
/**
|
||||
* Generated Plain Old Java Objects class for {@link FeelsLikeTemp} from JSON.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
public class FeelsLikeTemp {
|
||||
private Double day;
|
||||
private Double night;
|
||||
private Double eve;
|
||||
private Double morn;
|
||||
|
||||
public Double getDay() {
|
||||
return day;
|
||||
}
|
||||
|
||||
public void setDay(Double day) {
|
||||
this.day = day;
|
||||
}
|
||||
|
||||
public Double getNight() {
|
||||
return night;
|
||||
}
|
||||
|
||||
public void setNight(Double night) {
|
||||
this.night = night;
|
||||
}
|
||||
|
||||
public Double getEve() {
|
||||
return eve;
|
||||
}
|
||||
|
||||
public void setEve(Double eve) {
|
||||
this.eve = eve;
|
||||
}
|
||||
|
||||
public Double getMorn() {
|
||||
return morn;
|
||||
}
|
||||
|
||||
public void setMorn(Double morn) {
|
||||
this.morn = morn;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.openweathermap.internal.dto.forecast.daily;
|
||||
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.openweathermap.internal.dto.base.Weather;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* Generated Plain Old Java Objects class for {@link List} from JSON.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
public class List {
|
||||
private Integer dt;
|
||||
private Temp temp;
|
||||
@SerializedName("feels_like")
|
||||
private @Nullable FeelsLikeTemp feelsLikeTemp;
|
||||
private Double pressure;
|
||||
private Integer humidity;
|
||||
private java.util.List<Weather> weather;
|
||||
private Double speed;
|
||||
private Double deg;
|
||||
private @Nullable Double gust;
|
||||
private Integer clouds;
|
||||
private @Nullable Double rain;
|
||||
private @Nullable Double snow;
|
||||
|
||||
public Integer getDt() {
|
||||
return dt;
|
||||
}
|
||||
|
||||
public void setDt(Integer dt) {
|
||||
this.dt = dt;
|
||||
}
|
||||
|
||||
public Temp getTemp() {
|
||||
return temp;
|
||||
}
|
||||
|
||||
public void setTemp(Temp temp) {
|
||||
this.temp = temp;
|
||||
}
|
||||
|
||||
public @Nullable FeelsLikeTemp getFeelsLikeTemp() {
|
||||
return feelsLikeTemp;
|
||||
}
|
||||
|
||||
public void setFeelsLikeTemp(FeelsLikeTemp feelsLikeTemp) {
|
||||
this.feelsLikeTemp = feelsLikeTemp;
|
||||
}
|
||||
|
||||
public Double getPressure() {
|
||||
return pressure;
|
||||
}
|
||||
|
||||
public void setPressure(Double pressure) {
|
||||
this.pressure = pressure;
|
||||
}
|
||||
|
||||
public Integer getHumidity() {
|
||||
return humidity;
|
||||
}
|
||||
|
||||
public void setHumidity(Integer humidity) {
|
||||
this.humidity = humidity;
|
||||
}
|
||||
|
||||
public java.util.List<Weather> getWeather() {
|
||||
return weather;
|
||||
}
|
||||
|
||||
public void setWeather(java.util.List<Weather> weather) {
|
||||
this.weather = weather;
|
||||
}
|
||||
|
||||
public Double getSpeed() {
|
||||
return speed;
|
||||
}
|
||||
|
||||
public void setSpeed(Double speed) {
|
||||
this.speed = speed;
|
||||
}
|
||||
|
||||
public Double getDeg() {
|
||||
return deg;
|
||||
}
|
||||
|
||||
public void setDeg(Double deg) {
|
||||
this.deg = deg;
|
||||
}
|
||||
|
||||
public @Nullable Double getGust() {
|
||||
return gust;
|
||||
}
|
||||
|
||||
public void setGust(Double gust) {
|
||||
this.gust = speed;
|
||||
}
|
||||
|
||||
public Integer getClouds() {
|
||||
return clouds;
|
||||
}
|
||||
|
||||
public void setClouds(Integer clouds) {
|
||||
this.clouds = clouds;
|
||||
}
|
||||
|
||||
public @Nullable Double getRain() {
|
||||
return rain;
|
||||
}
|
||||
|
||||
public void setRain(Double rain) {
|
||||
this.rain = rain;
|
||||
}
|
||||
|
||||
public @Nullable Double getSnow() {
|
||||
return snow;
|
||||
}
|
||||
|
||||
public void setSnow(Double snow) {
|
||||
this.snow = snow;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.openweathermap.internal.dto.forecast.daily;
|
||||
|
||||
/**
|
||||
* Generated Plain Old Java Objects class for {@link Temp} from JSON.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
public class Temp {
|
||||
private Double day;
|
||||
private Double min;
|
||||
private Double max;
|
||||
private Double night;
|
||||
private Double eve;
|
||||
private Double morn;
|
||||
|
||||
public Double getDay() {
|
||||
return day;
|
||||
}
|
||||
|
||||
public void setDay(Double day) {
|
||||
this.day = day;
|
||||
}
|
||||
|
||||
public Double getMin() {
|
||||
return min;
|
||||
}
|
||||
|
||||
public void setMin(Double min) {
|
||||
this.min = min;
|
||||
}
|
||||
|
||||
public Double getMax() {
|
||||
return max;
|
||||
}
|
||||
|
||||
public void setMax(Double max) {
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
public Double getNight() {
|
||||
return night;
|
||||
}
|
||||
|
||||
public void setNight(Double night) {
|
||||
this.night = night;
|
||||
}
|
||||
|
||||
public Double getEve() {
|
||||
return eve;
|
||||
}
|
||||
|
||||
public void setEve(Double eve) {
|
||||
this.eve = eve;
|
||||
}
|
||||
|
||||
public Double getMorn() {
|
||||
return morn;
|
||||
}
|
||||
|
||||
public void setMorn(Double morn) {
|
||||
this.morn = morn;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.openweathermap.internal.dto.forecast.hourly;
|
||||
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.openweathermap.internal.dto.base.Clouds;
|
||||
import org.openhab.binding.openweathermap.internal.dto.base.Rain;
|
||||
import org.openhab.binding.openweathermap.internal.dto.base.Snow;
|
||||
import org.openhab.binding.openweathermap.internal.dto.base.Weather;
|
||||
import org.openhab.binding.openweathermap.internal.dto.base.Wind;
|
||||
import org.openhab.binding.openweathermap.internal.dto.weather.Main;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* Generated Plain Old Java Objects class for {@link List} from JSON.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
public class List {
|
||||
private Integer dt;
|
||||
private Main main;
|
||||
private java.util.List<Weather> weather;
|
||||
private Clouds clouds;
|
||||
private Wind wind;
|
||||
private @Nullable Rain rain;
|
||||
private @Nullable Snow snow;
|
||||
private Sys sys;
|
||||
@SerializedName("dt_txt")
|
||||
private String dtTxt;
|
||||
|
||||
public Integer getDt() {
|
||||
return dt;
|
||||
}
|
||||
|
||||
public void setDt(Integer dt) {
|
||||
this.dt = dt;
|
||||
}
|
||||
|
||||
public Main getMain() {
|
||||
return main;
|
||||
}
|
||||
|
||||
public void setMain(Main main) {
|
||||
this.main = main;
|
||||
}
|
||||
|
||||
public java.util.List<Weather> getWeather() {
|
||||
return weather;
|
||||
}
|
||||
|
||||
public void setWeather(java.util.List<Weather> weather) {
|
||||
this.weather = weather;
|
||||
}
|
||||
|
||||
public Clouds getClouds() {
|
||||
return clouds;
|
||||
}
|
||||
|
||||
public void setClouds(Clouds clouds) {
|
||||
this.clouds = clouds;
|
||||
}
|
||||
|
||||
public Wind getWind() {
|
||||
return wind;
|
||||
}
|
||||
|
||||
public void setWind(Wind wind) {
|
||||
this.wind = wind;
|
||||
}
|
||||
|
||||
public @Nullable Rain getRain() {
|
||||
return rain;
|
||||
}
|
||||
|
||||
public void setRain(Rain rain) {
|
||||
this.rain = rain;
|
||||
}
|
||||
|
||||
public @Nullable Snow getSnow() {
|
||||
return snow;
|
||||
}
|
||||
|
||||
public void setSnow(Snow snow) {
|
||||
this.snow = snow;
|
||||
}
|
||||
|
||||
public Sys getSys() {
|
||||
return sys;
|
||||
}
|
||||
|
||||
public void setSys(Sys sys) {
|
||||
this.sys = sys;
|
||||
}
|
||||
|
||||
public String getDtTxt() {
|
||||
return dtTxt;
|
||||
}
|
||||
|
||||
public void setDtTxt(String dtTxt) {
|
||||
this.dtTxt = dtTxt;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.openweathermap.internal.dto.forecast.hourly;
|
||||
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* Generated Plain Old Java Objects class for {@link Main} from JSON.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
public class Main {
|
||||
private Double temp;
|
||||
@SerializedName("feels_like")
|
||||
private @Nullable Double feelsLikeTemp;
|
||||
@SerializedName("temp_min")
|
||||
private Double tempMin;
|
||||
@SerializedName("temp_max")
|
||||
private Double tempMax;
|
||||
private Double pressure;
|
||||
@SerializedName("sea_level")
|
||||
private Double seaLevel;
|
||||
@SerializedName("grnd_level")
|
||||
private Double grndLevel;
|
||||
private Integer humidity;
|
||||
@SerializedName("temp_kf")
|
||||
private Integer tempKf;
|
||||
|
||||
public Double getTemp() {
|
||||
return temp;
|
||||
}
|
||||
|
||||
public void setTemp(Double temp) {
|
||||
this.temp = temp;
|
||||
}
|
||||
|
||||
public @Nullable Double getFeelsLikeTemp() {
|
||||
return feelsLikeTemp;
|
||||
}
|
||||
|
||||
public void setFeelsLikeTemp(Double feelsLikeTemp) {
|
||||
this.feelsLikeTemp = feelsLikeTemp;
|
||||
}
|
||||
|
||||
public Double getTempMin() {
|
||||
return tempMin;
|
||||
}
|
||||
|
||||
public void setTempMin(Double tempMin) {
|
||||
this.tempMin = tempMin;
|
||||
}
|
||||
|
||||
public Double getTempMax() {
|
||||
return tempMax;
|
||||
}
|
||||
|
||||
public void setTempMax(Double tempMax) {
|
||||
this.tempMax = tempMax;
|
||||
}
|
||||
|
||||
public Double getPressure() {
|
||||
return pressure;
|
||||
}
|
||||
|
||||
public void setPressure(Double pressure) {
|
||||
this.pressure = pressure;
|
||||
}
|
||||
|
||||
public Double getSeaLevel() {
|
||||
return seaLevel;
|
||||
}
|
||||
|
||||
public void setSeaLevel(Double seaLevel) {
|
||||
this.seaLevel = seaLevel;
|
||||
}
|
||||
|
||||
public Double getGrndLevel() {
|
||||
return grndLevel;
|
||||
}
|
||||
|
||||
public void setGrndLevel(Double grndLevel) {
|
||||
this.grndLevel = grndLevel;
|
||||
}
|
||||
|
||||
public Integer getHumidity() {
|
||||
return humidity;
|
||||
}
|
||||
|
||||
public void setHumidity(Integer humidity) {
|
||||
this.humidity = humidity;
|
||||
}
|
||||
|
||||
public Integer getTempKf() {
|
||||
return tempKf;
|
||||
}
|
||||
|
||||
public void setTempKf(Integer tempKf) {
|
||||
this.tempKf = tempKf;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.openweathermap.internal.dto.forecast.hourly;
|
||||
|
||||
/**
|
||||
* Generated Plain Old Java Objects class for {@link Sys} from JSON.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
public class Sys {
|
||||
private String pod;
|
||||
|
||||
public String getPod() {
|
||||
return pod;
|
||||
}
|
||||
|
||||
public void setPod(String pod) {
|
||||
this.pod = pod;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.openweathermap.internal.dto.weather;
|
||||
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* Generated Plain Old Java Objects class for {@link Main} from JSON.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
public class Main {
|
||||
private Double temp;
|
||||
@SerializedName("feels_like")
|
||||
private @Nullable Double feelsLikeTemp;
|
||||
private Double pressure;
|
||||
private Integer humidity;
|
||||
@SerializedName("temp_min")
|
||||
private Double tempMin;
|
||||
@SerializedName("temp_max")
|
||||
private Double tempMax;
|
||||
|
||||
public Double getTemp() {
|
||||
return temp;
|
||||
}
|
||||
|
||||
public void setTemp(Double temp) {
|
||||
this.temp = temp;
|
||||
}
|
||||
|
||||
public @Nullable Double getFeelsLikeTemp() {
|
||||
return feelsLikeTemp;
|
||||
}
|
||||
|
||||
public void setFeelsLikeTemp(Double feelsLikeTemp) {
|
||||
this.feelsLikeTemp = feelsLikeTemp;
|
||||
}
|
||||
|
||||
public Double getPressure() {
|
||||
return pressure;
|
||||
}
|
||||
|
||||
public void setPressure(Double pressure) {
|
||||
this.pressure = pressure;
|
||||
}
|
||||
|
||||
public Integer getHumidity() {
|
||||
return humidity;
|
||||
}
|
||||
|
||||
public void setHumidity(Integer humidity) {
|
||||
this.humidity = humidity;
|
||||
}
|
||||
|
||||
public Double getTempMin() {
|
||||
return tempMin;
|
||||
}
|
||||
|
||||
public void setTempMin(Double tempMin) {
|
||||
this.tempMin = tempMin;
|
||||
}
|
||||
|
||||
public Double getTempMax() {
|
||||
return tempMax;
|
||||
}
|
||||
|
||||
public void setTempMax(Double tempMax) {
|
||||
this.tempMax = tempMax;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.openweathermap.internal.dto.weather;
|
||||
|
||||
/**
|
||||
* Generated Plain Old Java Objects class for {@link Sys} from JSON.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
public class Sys {
|
||||
private Integer type;
|
||||
private Integer id;
|
||||
private Double message;
|
||||
private String country;
|
||||
private Integer sunrise;
|
||||
private Integer sunset;
|
||||
|
||||
public Integer getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(Integer type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Double getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(Double message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getCountry() {
|
||||
return country;
|
||||
}
|
||||
|
||||
public void setCountry(String country) {
|
||||
this.country = country;
|
||||
}
|
||||
|
||||
public Integer getSunrise() {
|
||||
return sunrise;
|
||||
}
|
||||
|
||||
public void setSunrise(Integer sunrise) {
|
||||
this.sunrise = sunrise;
|
||||
}
|
||||
|
||||
public Integer getSunset() {
|
||||
return sunset;
|
||||
}
|
||||
|
||||
public void setSunset(Integer sunset) {
|
||||
this.sunset = sunset;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.openweathermap.internal.factory;
|
||||
|
||||
import static org.openhab.binding.openweathermap.internal.OpenWeatherMapBindingConstants.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.openhab.binding.openweathermap.internal.discovery.OpenWeatherMapDiscoveryService;
|
||||
import org.openhab.binding.openweathermap.internal.handler.AbstractOpenWeatherMapHandler;
|
||||
import org.openhab.binding.openweathermap.internal.handler.OpenWeatherMapAPIHandler;
|
||||
import org.openhab.binding.openweathermap.internal.handler.OpenWeatherMapUVIndexHandler;
|
||||
import org.openhab.binding.openweathermap.internal.handler.OpenWeatherMapWeatherAndForecastHandler;
|
||||
import org.openhab.core.config.discovery.DiscoveryService;
|
||||
import org.openhab.core.i18n.LocaleProvider;
|
||||
import org.openhab.core.i18n.LocationProvider;
|
||||
import org.openhab.core.i18n.TimeZoneProvider;
|
||||
import org.openhab.core.i18n.TranslationProvider;
|
||||
import org.openhab.core.io.net.http.HttpClientFactory;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerFactory;
|
||||
import org.osgi.framework.ServiceRegistration;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
|
||||
/**
|
||||
* The {@link OpenWeatherMapHandlerFactory} is responsible for creating things and thing handlers.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.openweathermap")
|
||||
public class OpenWeatherMapHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections
|
||||
.unmodifiableSet(Stream.concat(OpenWeatherMapAPIHandler.SUPPORTED_THING_TYPES.stream(),
|
||||
AbstractOpenWeatherMapHandler.SUPPORTED_THING_TYPES.stream()).collect(Collectors.toSet()));
|
||||
|
||||
private final Map<ThingUID, @Nullable ServiceRegistration<?>> discoveryServiceRegs = new HashMap<>();
|
||||
private final HttpClient httpClient;
|
||||
private final LocaleProvider localeProvider;
|
||||
private final LocationProvider locationProvider;
|
||||
private final TranslationProvider i18nProvider;
|
||||
private final TimeZoneProvider timeZoneProvider;
|
||||
|
||||
@Activate
|
||||
public OpenWeatherMapHandlerFactory(final @Reference HttpClientFactory httpClientFactory,
|
||||
final @Reference LocaleProvider localeProvider, final @Reference LocationProvider locationProvider,
|
||||
final @Reference TranslationProvider i18nProvider, final @Reference TimeZoneProvider timeZoneProvider) {
|
||||
this.httpClient = httpClientFactory.getCommonHttpClient();
|
||||
this.localeProvider = localeProvider;
|
||||
this.locationProvider = locationProvider;
|
||||
this.i18nProvider = i18nProvider;
|
||||
this.timeZoneProvider = timeZoneProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||
|
||||
if (THING_TYPE_WEATHER_API.equals(thingTypeUID)) {
|
||||
OpenWeatherMapAPIHandler handler = new OpenWeatherMapAPIHandler((Bridge) thing, httpClient, localeProvider);
|
||||
// register discovery service
|
||||
OpenWeatherMapDiscoveryService discoveryService = new OpenWeatherMapDiscoveryService(handler,
|
||||
locationProvider, localeProvider, i18nProvider);
|
||||
discoveryServiceRegs.put(handler.getThing().getUID(), bundleContext
|
||||
.registerService(DiscoveryService.class.getName(), discoveryService, new Hashtable<>()));
|
||||
return handler;
|
||||
} else if (THING_TYPE_WEATHER_AND_FORECAST.equals(thingTypeUID)) {
|
||||
return new OpenWeatherMapWeatherAndForecastHandler(thing, timeZoneProvider);
|
||||
} else if (THING_TYPE_UVINDEX.equals(thingTypeUID)) {
|
||||
return new OpenWeatherMapUVIndexHandler(thing, timeZoneProvider);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void removeHandler(ThingHandler thingHandler) {
|
||||
if (thingHandler instanceof OpenWeatherMapAPIHandler) {
|
||||
ServiceRegistration<?> serviceReg = discoveryServiceRegs.remove(thingHandler.getThing().getUID());
|
||||
if (serviceReg != null) {
|
||||
// remove discovery service, if bridge handler is removed
|
||||
OpenWeatherMapDiscoveryService discoveryService = (OpenWeatherMapDiscoveryService) bundleContext
|
||||
.getService(serviceReg.getReference());
|
||||
serviceReg.unregister();
|
||||
if (discoveryService != null) {
|
||||
discoveryService.deactivate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.openweathermap.internal.handler;
|
||||
|
||||
import static org.openhab.binding.openweathermap.internal.OpenWeatherMapBindingConstants.*;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.measure.Unit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.openweathermap.internal.config.OpenWeatherMapLocationConfiguration;
|
||||
import org.openhab.binding.openweathermap.internal.connection.OpenWeatherMapCommunicationException;
|
||||
import org.openhab.binding.openweathermap.internal.connection.OpenWeatherMapConfigurationException;
|
||||
import org.openhab.binding.openweathermap.internal.connection.OpenWeatherMapConnection;
|
||||
import org.openhab.core.i18n.TimeZoneProvider;
|
||||
import org.openhab.core.library.types.DateTimeType;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.PointType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.types.RawType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.ChannelGroupUID;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.ThingStatusInfo;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerCallback;
|
||||
import org.openhab.core.thing.binding.builder.ChannelBuilder;
|
||||
import org.openhab.core.thing.type.ChannelGroupTypeUID;
|
||||
import org.openhab.core.thing.type.ChannelKind;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link AbstractOpenWeatherMapHandler} is responsible for handling commands, which are sent to one of the
|
||||
* channels.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class AbstractOpenWeatherMapHandler extends BaseThingHandler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(AbstractOpenWeatherMapHandler.class);
|
||||
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.unmodifiableSet(
|
||||
Stream.of(THING_TYPE_WEATHER_AND_FORECAST, THING_TYPE_UVINDEX).collect(Collectors.toSet()));
|
||||
|
||||
private final TimeZoneProvider timeZoneProvider;
|
||||
|
||||
// keeps track of the parsed location
|
||||
protected @Nullable PointType location;
|
||||
|
||||
public AbstractOpenWeatherMapHandler(Thing thing, final TimeZoneProvider timeZoneProvider) {
|
||||
super(thing);
|
||||
this.timeZoneProvider = timeZoneProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
OpenWeatherMapLocationConfiguration config = getConfigAs(OpenWeatherMapLocationConfiguration.class);
|
||||
|
||||
boolean configValid = true;
|
||||
if (config.location == null || config.location.trim().isEmpty()) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"@text/offline.conf-error-missing-location");
|
||||
configValid = false;
|
||||
}
|
||||
|
||||
try {
|
||||
location = new PointType(config.location);
|
||||
} catch (IllegalArgumentException e) {
|
||||
logger.warn("Error parsing 'location' parameter: {}", e.getMessage());
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"@text/offline.conf-error-parsing-location");
|
||||
location = null;
|
||||
configValid = false;
|
||||
}
|
||||
|
||||
if (configValid) {
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
if (command instanceof RefreshType) {
|
||||
updateChannel(channelUID);
|
||||
} else {
|
||||
logger.debug("The OpenWeatherMap binding is a read-only binding and cannot handle command '{}'.", command);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
|
||||
if (ThingStatus.ONLINE.equals(bridgeStatusInfo.getStatus())
|
||||
&& ThingStatusDetail.BRIDGE_OFFLINE.equals(getThing().getStatusInfo().getStatusDetail())) {
|
||||
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE);
|
||||
} else if (ThingStatus.OFFLINE.equals(bridgeStatusInfo.getStatus())
|
||||
&& !ThingStatus.OFFLINE.equals(getThing().getStatus())) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates OpenWeatherMap data for this location.
|
||||
*
|
||||
* @param connection {@link OpenWeatherMapConnection} instance
|
||||
*/
|
||||
public void updateData(OpenWeatherMapConnection connection) {
|
||||
try {
|
||||
if (requestData(connection)) {
|
||||
updateChannels();
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
}
|
||||
} catch (OpenWeatherMapCommunicationException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getLocalizedMessage());
|
||||
} catch (OpenWeatherMapConfigurationException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests the data from OpenWeatherMap API.
|
||||
*
|
||||
* @param connection {@link OpenWeatherMapConnection} instance
|
||||
* @return true, if the request for the OpenWeatherMap data was successful
|
||||
* @throws OpenWeatherMapCommunicationException
|
||||
* @throws OpenWeatherMapConfigurationException
|
||||
*/
|
||||
protected abstract boolean requestData(OpenWeatherMapConnection connection)
|
||||
throws OpenWeatherMapCommunicationException, OpenWeatherMapConfigurationException;
|
||||
|
||||
/**
|
||||
* Updates all channels of this handler from the latest OpenWeatherMap data retrieved.
|
||||
*/
|
||||
private void updateChannels() {
|
||||
for (Channel channel : getThing().getChannels()) {
|
||||
ChannelUID channelUID = channel.getUID();
|
||||
if (ChannelKind.STATE.equals(channel.getKind()) && channelUID.isInGroup() && channelUID.getGroupId() != null
|
||||
&& isLinked(channelUID)) {
|
||||
updateChannel(channelUID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the channel with the given UID from the latest OpenWeatherMap data retrieved.
|
||||
*
|
||||
* @param channelUID UID of the channel
|
||||
*/
|
||||
protected abstract void updateChannel(ChannelUID channelUID);
|
||||
|
||||
protected State getDateTimeTypeState(@Nullable Integer value) {
|
||||
return (value == null) ? UnDefType.UNDEF
|
||||
: new DateTimeType(ZonedDateTime.ofInstant(Instant.ofEpochSecond(value.longValue()),
|
||||
timeZoneProvider.getTimeZone()));
|
||||
}
|
||||
|
||||
protected State getDecimalTypeState(@Nullable Double value) {
|
||||
return (value == null) ? UnDefType.UNDEF : new DecimalType(value);
|
||||
}
|
||||
|
||||
protected State getPointTypeState(@Nullable Double latitude, @Nullable Double longitude) {
|
||||
return ((latitude == null) || (longitude == null)) ? UnDefType.UNDEF
|
||||
: new PointType(new DecimalType(latitude), new DecimalType(longitude));
|
||||
}
|
||||
|
||||
protected State getRawTypeState(@Nullable RawType image) {
|
||||
return (image == null) ? UnDefType.UNDEF : image;
|
||||
}
|
||||
|
||||
protected State getStringTypeState(@Nullable String value) {
|
||||
return (value == null) ? UnDefType.UNDEF : new StringType(value);
|
||||
}
|
||||
|
||||
protected State getQuantityTypeState(@Nullable Number value, Unit<?> unit) {
|
||||
return (value == null) ? UnDefType.UNDEF : new QuantityType<>(value, unit);
|
||||
}
|
||||
|
||||
protected List<Channel> createChannelsForGroup(String channelGroupId, ChannelGroupTypeUID channelGroupTypeUID) {
|
||||
logger.debug("Building channel group '{}' for thing '{}'.", channelGroupId, getThing().getUID());
|
||||
List<Channel> channels = new ArrayList<>();
|
||||
ThingHandlerCallback callback = getCallback();
|
||||
if (callback != null) {
|
||||
for (ChannelBuilder channelBuilder : callback.createChannelBuilders(
|
||||
new ChannelGroupUID(getThing().getUID(), channelGroupId), channelGroupTypeUID)) {
|
||||
Channel newChannel = channelBuilder.build(),
|
||||
existingChannel = getThing().getChannel(newChannel.getUID().getId());
|
||||
if (existingChannel != null) {
|
||||
logger.trace("Thing '{}' already has an existing channel '{}'. Omit adding new channel '{}'.",
|
||||
getThing().getUID(), existingChannel.getUID(), newChannel.getUID());
|
||||
continue;
|
||||
}
|
||||
channels.add(newChannel);
|
||||
}
|
||||
}
|
||||
return channels;
|
||||
}
|
||||
|
||||
protected List<Channel> removeChannelsOfGroup(String channelGroupId) {
|
||||
logger.debug("Removing channel group '{}' from thing '{}'.", channelGroupId, getThing().getUID());
|
||||
return getThing().getChannelsOfGroup(channelGroupId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.openweathermap.internal.handler;
|
||||
|
||||
import static org.openhab.binding.openweathermap.internal.OpenWeatherMapBindingConstants.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.openhab.binding.openweathermap.internal.config.OpenWeatherMapAPIConfiguration;
|
||||
import org.openhab.binding.openweathermap.internal.connection.OpenWeatherMapConnection;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.i18n.LocaleProvider;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.binding.BaseBridgeHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link OpenWeatherMapAPIHandler} is responsible for accessing the OpenWeatherMap API.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OpenWeatherMapAPIHandler extends BaseBridgeHandler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(OpenWeatherMapAPIHandler.class);
|
||||
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_WEATHER_API);
|
||||
|
||||
private static final long INITIAL_DELAY_IN_SECONDS = 15;
|
||||
|
||||
private @Nullable ScheduledFuture<?> refreshJob;
|
||||
|
||||
private final HttpClient httpClient;
|
||||
private final LocaleProvider localeProvider;
|
||||
private @NonNullByDefault({}) OpenWeatherMapConnection connection;
|
||||
|
||||
// keeps track of the parsed config
|
||||
private @NonNullByDefault({}) OpenWeatherMapAPIConfiguration config;
|
||||
|
||||
public OpenWeatherMapAPIHandler(Bridge bridge, HttpClient httpClient, LocaleProvider localeProvider) {
|
||||
super(bridge);
|
||||
this.httpClient = httpClient;
|
||||
this.localeProvider = localeProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
logger.debug("Initialize OpenWeatherMap API handler '{}'.", getThing().getUID());
|
||||
config = getConfigAs(OpenWeatherMapAPIConfiguration.class);
|
||||
|
||||
boolean configValid = true;
|
||||
if (config.apikey == null || config.apikey.trim().isEmpty()) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"@text/offline.conf-error-missing-apikey");
|
||||
configValid = false;
|
||||
}
|
||||
int refreshInterval = config.refreshInterval;
|
||||
if (refreshInterval < 10) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"@text/offline.conf-error-not-supported-refreshInterval");
|
||||
configValid = false;
|
||||
}
|
||||
String language = config.language;
|
||||
if (language != null && !(language = language.trim()).isEmpty()) {
|
||||
if (!OpenWeatherMapAPIConfiguration.SUPPORTED_LANGUAGES.contains(language.toLowerCase())) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"@text/offline.conf-error-not-supported-language");
|
||||
configValid = false;
|
||||
}
|
||||
} else {
|
||||
language = localeProvider.getLocale().getLanguage();
|
||||
if (OpenWeatherMapAPIConfiguration.SUPPORTED_LANGUAGES.contains(language)) {
|
||||
logger.debug("Language set to '{}'.", language);
|
||||
Configuration editConfig = editConfiguration();
|
||||
editConfig.put(CONFIG_LANGUAGE, language);
|
||||
updateConfiguration(editConfig);
|
||||
}
|
||||
}
|
||||
|
||||
if (configValid) {
|
||||
connection = new OpenWeatherMapConnection(this, httpClient);
|
||||
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
|
||||
ScheduledFuture<?> localRefreshJob = refreshJob;
|
||||
if (localRefreshJob == null || localRefreshJob.isCancelled()) {
|
||||
logger.debug("Start refresh job at interval {} min.", refreshInterval);
|
||||
refreshJob = scheduler.scheduleWithFixedDelay(this::updateThings, INITIAL_DELAY_IN_SECONDS,
|
||||
TimeUnit.MINUTES.toSeconds(refreshInterval), TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
logger.debug("Dispose OpenWeatherMap API handler '{}'.", getThing().getUID());
|
||||
ScheduledFuture<?> localRefreshJob = refreshJob;
|
||||
if (localRefreshJob != null && !localRefreshJob.isCancelled()) {
|
||||
logger.debug("Stop refresh job.");
|
||||
if (localRefreshJob.cancel(true)) {
|
||||
refreshJob = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
if (command instanceof RefreshType) {
|
||||
scheduler.schedule(this::updateThings, INITIAL_DELAY_IN_SECONDS, TimeUnit.SECONDS);
|
||||
} else {
|
||||
logger.debug("The OpenWeatherMap binding is a read-only binding and cannot handle command '{}'.", command);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void childHandlerInitialized(ThingHandler childHandler, Thing childThing) {
|
||||
scheduler.schedule(() -> {
|
||||
updateThing((AbstractOpenWeatherMapHandler) childHandler, childThing);
|
||||
determineBridgeStatus();
|
||||
}, INITIAL_DELAY_IN_SECONDS, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void childHandlerDisposed(ThingHandler childHandler, Thing childThing) {
|
||||
determineBridgeStatus();
|
||||
}
|
||||
|
||||
private void determineBridgeStatus() {
|
||||
ThingStatus status = ThingStatus.OFFLINE;
|
||||
for (Thing thing : getThing().getThings()) {
|
||||
if (ThingStatus.ONLINE.equals(thing.getStatus())) {
|
||||
status = ThingStatus.ONLINE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
updateStatus(status);
|
||||
}
|
||||
|
||||
private void updateThings() {
|
||||
ThingStatus status = ThingStatus.OFFLINE;
|
||||
for (Thing thing : getThing().getThings()) {
|
||||
if (ThingStatus.ONLINE.equals(updateThing((AbstractOpenWeatherMapHandler) thing.getHandler(), thing))) {
|
||||
status = ThingStatus.ONLINE;
|
||||
}
|
||||
}
|
||||
updateStatus(status);
|
||||
}
|
||||
|
||||
private ThingStatus updateThing(@Nullable AbstractOpenWeatherMapHandler handler, Thing thing) {
|
||||
if (handler != null && connection != null) {
|
||||
handler.updateData(connection);
|
||||
return thing.getStatus();
|
||||
} else {
|
||||
logger.debug("Cannot update weather data of thing '{}' as location handler is null.", thing.getUID());
|
||||
return ThingStatus.OFFLINE;
|
||||
}
|
||||
}
|
||||
|
||||
public OpenWeatherMapAPIConfiguration getOpenWeatherMapAPIConfig() {
|
||||
return config;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.openweathermap.internal.handler;
|
||||
|
||||
import static org.openhab.binding.openweathermap.internal.OpenWeatherMapBindingConstants.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.openweathermap.internal.config.OpenWeatherMapUVIndexConfiguration;
|
||||
import org.openhab.binding.openweathermap.internal.connection.OpenWeatherMapCommunicationException;
|
||||
import org.openhab.binding.openweathermap.internal.connection.OpenWeatherMapConfigurationException;
|
||||
import org.openhab.binding.openweathermap.internal.connection.OpenWeatherMapConnection;
|
||||
import org.openhab.binding.openweathermap.internal.dto.OpenWeatherMapJsonUVIndexData;
|
||||
import org.openhab.core.i18n.TimeZoneProvider;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.binding.builder.ThingBuilder;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
/**
|
||||
* The {@link OpenWeatherMapUVIndexHandler} is responsible for handling commands, which are sent to one of the
|
||||
* channels.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OpenWeatherMapUVIndexHandler extends AbstractOpenWeatherMapHandler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(OpenWeatherMapUVIndexHandler.class);
|
||||
|
||||
private static final String CHANNEL_GROUP_FORECAST_PREFIX = "forecastDay";
|
||||
private static final Pattern CHANNEL_GROUP_FORECAST_PREFIX_PATTERN = Pattern
|
||||
.compile(CHANNEL_GROUP_FORECAST_PREFIX + "([0-9]*)");
|
||||
|
||||
// keeps track of the parsed count
|
||||
private int forecastDays = 6;
|
||||
|
||||
private @Nullable OpenWeatherMapJsonUVIndexData uvindexData;
|
||||
private @Nullable List<OpenWeatherMapJsonUVIndexData> uvindexForecastData;
|
||||
|
||||
public OpenWeatherMapUVIndexHandler(Thing thing, final TimeZoneProvider timeZoneProvider) {
|
||||
super(thing, timeZoneProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
super.initialize();
|
||||
logger.debug("Initialize OpenWeatherMapUVIndexHandler handler '{}'.", getThing().getUID());
|
||||
OpenWeatherMapUVIndexConfiguration config = getConfigAs(OpenWeatherMapUVIndexConfiguration.class);
|
||||
|
||||
boolean configValid = true;
|
||||
int newForecastDays = config.forecastDays;
|
||||
if (newForecastDays < 1 || newForecastDays > 8) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"@text/offline.conf-error-not-supported-uvindex-number-of-days");
|
||||
configValid = false;
|
||||
}
|
||||
|
||||
if (configValid) {
|
||||
logger.debug("Rebuilding thing '{}'.", getThing().getUID());
|
||||
List<Channel> toBeAddedChannels = new ArrayList<>();
|
||||
List<Channel> toBeRemovedChannels = new ArrayList<>();
|
||||
if (forecastDays != newForecastDays) {
|
||||
logger.debug("Rebuilding UV index channel groups.");
|
||||
if (forecastDays > newForecastDays) {
|
||||
if (newForecastDays < 2) {
|
||||
toBeRemovedChannels.addAll(removeChannelsOfGroup(CHANNEL_GROUP_FORECAST_TOMORROW));
|
||||
}
|
||||
for (int i = newForecastDays; i < forecastDays; ++i) {
|
||||
toBeRemovedChannels
|
||||
.addAll(removeChannelsOfGroup(CHANNEL_GROUP_FORECAST_PREFIX + Integer.toString(i)));
|
||||
}
|
||||
} else {
|
||||
if (forecastDays <= 1 && newForecastDays > 1) {
|
||||
toBeAddedChannels.addAll(
|
||||
createChannelsForGroup(CHANNEL_GROUP_FORECAST_TOMORROW, CHANNEL_GROUP_TYPE_UVINDEX));
|
||||
}
|
||||
for (int i = (forecastDays < 2) ? 2 : forecastDays; i < newForecastDays; ++i) {
|
||||
toBeAddedChannels.addAll(createChannelsForGroup(
|
||||
CHANNEL_GROUP_FORECAST_PREFIX + Integer.toString(i), CHANNEL_GROUP_TYPE_UVINDEX));
|
||||
}
|
||||
}
|
||||
forecastDays = newForecastDays;
|
||||
}
|
||||
ThingBuilder builder = editThing().withoutChannels(toBeRemovedChannels);
|
||||
for (Channel channel : toBeAddedChannels) {
|
||||
builder.withChannel(channel);
|
||||
}
|
||||
updateThing(builder.build());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean requestData(OpenWeatherMapConnection connection)
|
||||
throws OpenWeatherMapCommunicationException, OpenWeatherMapConfigurationException {
|
||||
logger.debug("Update UV Index data of thing '{}'.", getThing().getUID());
|
||||
try {
|
||||
uvindexData = connection.getUVIndexData(location);
|
||||
if (forecastDays > 0) {
|
||||
uvindexForecastData = connection.getUVIndexForecastData(location, forecastDays);
|
||||
}
|
||||
return true;
|
||||
} catch (JsonSyntaxException e) {
|
||||
logger.debug("JsonSyntaxException occurred during execution: {}", e.getLocalizedMessage(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateChannel(ChannelUID channelUID) {
|
||||
switch (channelUID.getGroupId()) {
|
||||
case CHANNEL_GROUP_CURRENT_UVINDEX:
|
||||
updateUVIndexChannel(channelUID);
|
||||
break;
|
||||
case CHANNEL_GROUP_FORECAST_TOMORROW:
|
||||
updateUVIndexForecastChannel(channelUID, 1);
|
||||
break;
|
||||
default:
|
||||
Matcher m = CHANNEL_GROUP_FORECAST_PREFIX_PATTERN.matcher(channelUID.getGroupId());
|
||||
int i;
|
||||
if (m.find() && (i = Integer.parseInt(m.group(1))) > 1 && i <= 8) {
|
||||
updateUVIndexForecastChannel(channelUID, i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the channel from the last OpenWeatherMap data retrieved.
|
||||
*
|
||||
* @param channelUID the id identifying the channel to be updated
|
||||
*/
|
||||
private void updateUVIndexChannel(ChannelUID channelUID) {
|
||||
String channelId = channelUID.getIdWithoutGroup();
|
||||
String channelGroupId = channelUID.getGroupId();
|
||||
OpenWeatherMapJsonUVIndexData localUVIndexData = uvindexData;
|
||||
if (localUVIndexData != null) {
|
||||
State state = UnDefType.UNDEF;
|
||||
switch (channelId) {
|
||||
case CHANNEL_TIME_STAMP:
|
||||
state = getDateTimeTypeState(localUVIndexData.getDate());
|
||||
break;
|
||||
case CHANNEL_UVINDEX:
|
||||
state = getDecimalTypeState(localUVIndexData.getValue());
|
||||
break;
|
||||
}
|
||||
logger.debug("Update channel '{}' of group '{}' with new state '{}'.", channelId, channelGroupId, state);
|
||||
updateState(channelUID, state);
|
||||
} else {
|
||||
logger.debug("No UV Index data available to update channel '{}' of group '{}'.", channelId, channelGroupId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the channel from the last OpenWeatherMap data retrieved.
|
||||
*
|
||||
* @param channelUID the id identifying the channel to be updated
|
||||
* @param count
|
||||
*/
|
||||
private void updateUVIndexForecastChannel(ChannelUID channelUID, int count) {
|
||||
String channelId = channelUID.getIdWithoutGroup();
|
||||
String channelGroupId = channelUID.getGroupId();
|
||||
List<OpenWeatherMapJsonUVIndexData> localUVIndexForecastData = uvindexForecastData;
|
||||
if (localUVIndexForecastData != null && localUVIndexForecastData.size() >= count) {
|
||||
OpenWeatherMapJsonUVIndexData forecastData = localUVIndexForecastData.get(count - 1);
|
||||
State state = UnDefType.UNDEF;
|
||||
switch (channelId) {
|
||||
case CHANNEL_TIME_STAMP:
|
||||
state = getDateTimeTypeState(forecastData.getDate());
|
||||
break;
|
||||
case CHANNEL_UVINDEX:
|
||||
state = getDecimalTypeState(forecastData.getValue());
|
||||
break;
|
||||
}
|
||||
logger.debug("Update channel '{}' of group '{}' with new state '{}'.", channelId, channelGroupId, state);
|
||||
updateState(channelUID, state);
|
||||
} else {
|
||||
logger.debug("No UV Index data available to update channel '{}' of group '{}'.", channelId, channelGroupId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,497 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.openweathermap.internal.handler;
|
||||
|
||||
import static org.openhab.binding.openweathermap.internal.OpenWeatherMapBindingConstants.*;
|
||||
import static org.openhab.core.library.unit.MetricPrefix.*;
|
||||
import static org.openhab.core.library.unit.SIUnits.*;
|
||||
import static org.openhab.core.library.unit.SmartHomeUnits.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpResponseException;
|
||||
import org.openhab.binding.openweathermap.internal.config.OpenWeatherMapWeatherAndForecastConfiguration;
|
||||
import org.openhab.binding.openweathermap.internal.connection.OpenWeatherMapCommunicationException;
|
||||
import org.openhab.binding.openweathermap.internal.connection.OpenWeatherMapConfigurationException;
|
||||
import org.openhab.binding.openweathermap.internal.connection.OpenWeatherMapConnection;
|
||||
import org.openhab.binding.openweathermap.internal.dto.OpenWeatherMapJsonDailyForecastData;
|
||||
import org.openhab.binding.openweathermap.internal.dto.OpenWeatherMapJsonHourlyForecastData;
|
||||
import org.openhab.binding.openweathermap.internal.dto.OpenWeatherMapJsonWeatherData;
|
||||
import org.openhab.binding.openweathermap.internal.dto.base.Rain;
|
||||
import org.openhab.binding.openweathermap.internal.dto.base.Snow;
|
||||
import org.openhab.binding.openweathermap.internal.dto.forecast.daily.FeelsLikeTemp;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.i18n.TimeZoneProvider;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.binding.builder.ThingBuilder;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
/**
|
||||
* The {@link OpenWeatherMapWeatherAndForecastHandler} is responsible for handling commands, which are sent to one of
|
||||
* the channels.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OpenWeatherMapWeatherAndForecastHandler extends AbstractOpenWeatherMapHandler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(OpenWeatherMapWeatherAndForecastHandler.class);
|
||||
|
||||
private static final String CHANNEL_GROUP_HOURLY_FORECAST_PREFIX = "forecastHours";
|
||||
private static final String CHANNEL_GROUP_DAILY_FORECAST_PREFIX = "forecastDay";
|
||||
private static final Pattern CHANNEL_GROUP_HOURLY_FORECAST_PREFIX_PATTERN = Pattern
|
||||
.compile(CHANNEL_GROUP_HOURLY_FORECAST_PREFIX + "([0-9]*)");
|
||||
private static final Pattern CHANNEL_GROUP_DAILY_FORECAST_PREFIX_PATTERN = Pattern
|
||||
.compile(CHANNEL_GROUP_DAILY_FORECAST_PREFIX + "([0-9]*)");
|
||||
|
||||
// keeps track of the parsed counts
|
||||
private int forecastHours = 24;
|
||||
private int forecastDays = 6;
|
||||
|
||||
private @Nullable OpenWeatherMapJsonWeatherData weatherData;
|
||||
private @Nullable OpenWeatherMapJsonHourlyForecastData hourlyForecastData;
|
||||
private @Nullable OpenWeatherMapJsonDailyForecastData dailyForecastData;
|
||||
|
||||
public OpenWeatherMapWeatherAndForecastHandler(Thing thing, final TimeZoneProvider timeZoneProvider) {
|
||||
super(thing, timeZoneProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
super.initialize();
|
||||
logger.debug("Initialize OpenWeatherMapWeatherAndForecastHandler handler '{}'.", getThing().getUID());
|
||||
OpenWeatherMapWeatherAndForecastConfiguration config = getConfigAs(
|
||||
OpenWeatherMapWeatherAndForecastConfiguration.class);
|
||||
|
||||
boolean configValid = true;
|
||||
int newForecastHours = config.forecastHours;
|
||||
if (newForecastHours < 0 || newForecastHours > 120 || newForecastHours % 3 != 0) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"@text/offline.conf-error-not-supported-number-of-hours");
|
||||
configValid = false;
|
||||
}
|
||||
int newForecastDays = config.forecastDays;
|
||||
if (newForecastDays < 0 || newForecastDays > 16) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"@text/offline.conf-error-not-supported-number-of-days");
|
||||
configValid = false;
|
||||
}
|
||||
|
||||
if (configValid) {
|
||||
logger.debug("Rebuilding thing '{}'.", getThing().getUID());
|
||||
List<Channel> toBeAddedChannels = new ArrayList<>();
|
||||
List<Channel> toBeRemovedChannels = new ArrayList<>();
|
||||
if (forecastHours != newForecastHours) {
|
||||
logger.debug("Rebuilding hourly forecast channel groups.");
|
||||
if (forecastHours > newForecastHours) {
|
||||
for (int i = newForecastHours + 3; i <= forecastHours; i += 3) {
|
||||
toBeRemovedChannels.addAll(removeChannelsOfGroup(
|
||||
CHANNEL_GROUP_HOURLY_FORECAST_PREFIX + ((i < 10) ? "0" : "") + Integer.toString(i)));
|
||||
}
|
||||
} else {
|
||||
for (int i = forecastHours + 3; i <= newForecastHours; i += 3) {
|
||||
toBeAddedChannels.addAll(createChannelsForGroup(
|
||||
CHANNEL_GROUP_HOURLY_FORECAST_PREFIX + ((i < 10) ? "0" : "") + Integer.toString(i),
|
||||
CHANNEL_GROUP_TYPE_HOURLY_FORECAST));
|
||||
}
|
||||
}
|
||||
forecastHours = newForecastHours;
|
||||
}
|
||||
if (forecastDays != newForecastDays) {
|
||||
logger.debug("Rebuilding daily forecast channel groups.");
|
||||
if (forecastDays > newForecastDays) {
|
||||
if (newForecastDays < 1) {
|
||||
toBeRemovedChannels.addAll(removeChannelsOfGroup(CHANNEL_GROUP_FORECAST_TODAY));
|
||||
}
|
||||
if (newForecastDays < 2) {
|
||||
toBeRemovedChannels.addAll(removeChannelsOfGroup(CHANNEL_GROUP_FORECAST_TOMORROW));
|
||||
}
|
||||
for (int i = newForecastDays; i < forecastDays; ++i) {
|
||||
toBeRemovedChannels.addAll(
|
||||
removeChannelsOfGroup(CHANNEL_GROUP_DAILY_FORECAST_PREFIX + Integer.toString(i)));
|
||||
}
|
||||
} else {
|
||||
if (forecastDays == 0 && newForecastDays > 0) {
|
||||
toBeAddedChannels.addAll(createChannelsForGroup(CHANNEL_GROUP_FORECAST_TODAY,
|
||||
CHANNEL_GROUP_TYPE_DAILY_FORECAST));
|
||||
}
|
||||
if (forecastDays <= 1 && newForecastDays > 1) {
|
||||
toBeAddedChannels.addAll(createChannelsForGroup(CHANNEL_GROUP_FORECAST_TOMORROW,
|
||||
CHANNEL_GROUP_TYPE_DAILY_FORECAST));
|
||||
}
|
||||
for (int i = (forecastDays < 2) ? 2 : forecastDays; i < newForecastDays; ++i) {
|
||||
toBeAddedChannels.addAll(
|
||||
createChannelsForGroup(CHANNEL_GROUP_DAILY_FORECAST_PREFIX + Integer.toString(i),
|
||||
CHANNEL_GROUP_TYPE_DAILY_FORECAST));
|
||||
}
|
||||
}
|
||||
forecastDays = newForecastDays;
|
||||
}
|
||||
ThingBuilder builder = editThing().withoutChannels(toBeRemovedChannels);
|
||||
for (Channel channel : toBeAddedChannels) {
|
||||
builder.withChannel(channel);
|
||||
}
|
||||
updateThing(builder.build());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean requestData(OpenWeatherMapConnection connection)
|
||||
throws OpenWeatherMapCommunicationException, OpenWeatherMapConfigurationException {
|
||||
logger.debug("Update weather and forecast data of thing '{}'.", getThing().getUID());
|
||||
try {
|
||||
weatherData = connection.getWeatherData(location);
|
||||
if (forecastHours > 0) {
|
||||
hourlyForecastData = connection.getHourlyForecastData(location, forecastHours / 3);
|
||||
}
|
||||
if (forecastDays > 0) {
|
||||
try {
|
||||
dailyForecastData = connection.getDailyForecastData(location, forecastDays);
|
||||
} catch (OpenWeatherMapConfigurationException e) {
|
||||
if (e.getCause() instanceof HttpResponseException) {
|
||||
forecastDays = 0;
|
||||
Configuration editConfig = editConfiguration();
|
||||
editConfig.put(CONFIG_FORECAST_DAYS, 0);
|
||||
updateConfiguration(editConfig);
|
||||
logger.debug("Removing daily forecast channel groups.");
|
||||
List<Channel> channels = getThing().getChannels().stream()
|
||||
.filter(c -> CHANNEL_GROUP_FORECAST_TODAY.equals(c.getUID().getGroupId())
|
||||
|| CHANNEL_GROUP_FORECAST_TOMORROW.equals(c.getUID().getGroupId())
|
||||
|| c.getUID().getGroupId().startsWith(CHANNEL_GROUP_DAILY_FORECAST_PREFIX))
|
||||
.collect(Collectors.toList());
|
||||
updateThing(editThing().withoutChannels(channels).build());
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} catch (JsonSyntaxException e) {
|
||||
logger.debug("JsonSyntaxException occurred during execution: {}", e.getLocalizedMessage(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateChannel(ChannelUID channelUID) {
|
||||
String channelGroupId = channelUID.getGroupId();
|
||||
switch (channelGroupId) {
|
||||
case CHANNEL_GROUP_STATION:
|
||||
case CHANNEL_GROUP_CURRENT_WEATHER:
|
||||
updateCurrentChannel(channelUID);
|
||||
break;
|
||||
case CHANNEL_GROUP_FORECAST_TODAY:
|
||||
updateDailyForecastChannel(channelUID, 0);
|
||||
break;
|
||||
case CHANNEL_GROUP_FORECAST_TOMORROW:
|
||||
updateDailyForecastChannel(channelUID, 1);
|
||||
break;
|
||||
default:
|
||||
int i;
|
||||
Matcher hourlyForecastMatcher = CHANNEL_GROUP_HOURLY_FORECAST_PREFIX_PATTERN.matcher(channelGroupId);
|
||||
if (hourlyForecastMatcher.find() && (i = Integer.parseInt(hourlyForecastMatcher.group(1))) >= 3
|
||||
&& i <= 120) {
|
||||
updateHourlyForecastChannel(channelUID, (i / 3) - 1);
|
||||
break;
|
||||
}
|
||||
Matcher dailyForecastMatcher = CHANNEL_GROUP_DAILY_FORECAST_PREFIX_PATTERN.matcher(channelGroupId);
|
||||
if (dailyForecastMatcher.find() && (i = Integer.parseInt(dailyForecastMatcher.group(1))) > 1
|
||||
&& i <= 16) {
|
||||
updateDailyForecastChannel(channelUID, i);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the channel from the last OpenWeatherMap data retrieved.
|
||||
*
|
||||
* @param channelUID the id identifying the channel to be updated
|
||||
*/
|
||||
private void updateCurrentChannel(ChannelUID channelUID) {
|
||||
String channelId = channelUID.getIdWithoutGroup();
|
||||
String channelGroupId = channelUID.getGroupId();
|
||||
OpenWeatherMapJsonWeatherData localWeatherData = weatherData;
|
||||
if (localWeatherData != null) {
|
||||
State state = UnDefType.UNDEF;
|
||||
switch (channelId) {
|
||||
case CHANNEL_STATION_ID:
|
||||
state = getStringTypeState(localWeatherData.getId().toString());
|
||||
break;
|
||||
case CHANNEL_STATION_NAME:
|
||||
state = getStringTypeState(localWeatherData.getName());
|
||||
break;
|
||||
case CHANNEL_STATION_LOCATION:
|
||||
state = getPointTypeState(localWeatherData.getCoord().getLat(),
|
||||
localWeatherData.getCoord().getLon());
|
||||
break;
|
||||
case CHANNEL_TIME_STAMP:
|
||||
state = getDateTimeTypeState(localWeatherData.getDt());
|
||||
break;
|
||||
case CHANNEL_CONDITION:
|
||||
if (!localWeatherData.getWeather().isEmpty()) {
|
||||
state = getStringTypeState(localWeatherData.getWeather().get(0).getDescription());
|
||||
}
|
||||
break;
|
||||
case CHANNEL_CONDITION_ID:
|
||||
if (!localWeatherData.getWeather().isEmpty()) {
|
||||
state = getStringTypeState(localWeatherData.getWeather().get(0).getId().toString());
|
||||
}
|
||||
break;
|
||||
case CHANNEL_CONDITION_ICON:
|
||||
if (!localWeatherData.getWeather().isEmpty()) {
|
||||
state = getRawTypeState(OpenWeatherMapConnection
|
||||
.getWeatherIcon(localWeatherData.getWeather().get(0).getIcon()));
|
||||
}
|
||||
break;
|
||||
case CHANNEL_CONDITION_ICON_ID:
|
||||
if (!localWeatherData.getWeather().isEmpty()) {
|
||||
state = getStringTypeState(localWeatherData.getWeather().get(0).getIcon());
|
||||
}
|
||||
break;
|
||||
case CHANNEL_TEMPERATURE:
|
||||
state = getQuantityTypeState(localWeatherData.getMain().getTemp(), CELSIUS);
|
||||
break;
|
||||
case CHANNEL_APPARENT_TEMPERATURE:
|
||||
state = getQuantityTypeState(localWeatherData.getMain().getFeelsLikeTemp(), CELSIUS);
|
||||
break;
|
||||
case CHANNEL_PRESSURE:
|
||||
state = getQuantityTypeState(localWeatherData.getMain().getPressure(), HECTO(PASCAL));
|
||||
break;
|
||||
case CHANNEL_HUMIDITY:
|
||||
state = getQuantityTypeState(localWeatherData.getMain().getHumidity(), PERCENT);
|
||||
break;
|
||||
case CHANNEL_WIND_SPEED:
|
||||
state = getQuantityTypeState(localWeatherData.getWind().getSpeed(), METRE_PER_SECOND);
|
||||
break;
|
||||
case CHANNEL_WIND_DIRECTION:
|
||||
state = getQuantityTypeState(localWeatherData.getWind().getDeg(), DEGREE_ANGLE);
|
||||
break;
|
||||
case CHANNEL_GUST_SPEED:
|
||||
state = getQuantityTypeState(localWeatherData.getWind().getGust(), METRE_PER_SECOND);
|
||||
break;
|
||||
case CHANNEL_CLOUDINESS:
|
||||
state = getQuantityTypeState(localWeatherData.getClouds().getAll(), PERCENT);
|
||||
break;
|
||||
case CHANNEL_RAIN:
|
||||
Rain rain = localWeatherData.getRain();
|
||||
state = getQuantityTypeState(rain == null ? 0 : rain.getVolume(), MILLI(METRE));
|
||||
break;
|
||||
case CHANNEL_SNOW:
|
||||
Snow snow = localWeatherData.getSnow();
|
||||
state = getQuantityTypeState(snow == null ? 0 : snow.getVolume(), MILLI(METRE));
|
||||
break;
|
||||
case CHANNEL_VISIBILITY:
|
||||
Integer localVisibility = localWeatherData.getVisibility();
|
||||
state = localVisibility == null ? UnDefType.UNDEF
|
||||
: new QuantityType<>(localVisibility, METRE).toUnit(KILO(METRE));
|
||||
if (state == null) {
|
||||
logger.debug("State conversion failed, cannot update state.");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
logger.debug("Update channel '{}' of group '{}' with new state '{}'.", channelId, channelGroupId, state);
|
||||
updateState(channelUID, state);
|
||||
} else {
|
||||
logger.debug("No weather data available to update channel '{}' of group '{}'.", channelId, channelGroupId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the channel from the last OpenWeatherMap data retrieved.
|
||||
*
|
||||
* @param channelUID the id identifying the channel to be updated
|
||||
* @param count
|
||||
*/
|
||||
private void updateHourlyForecastChannel(ChannelUID channelUID, int count) {
|
||||
String channelId = channelUID.getIdWithoutGroup();
|
||||
String channelGroupId = channelUID.getGroupId();
|
||||
OpenWeatherMapJsonHourlyForecastData localHourlyForecastData = hourlyForecastData;
|
||||
if (localHourlyForecastData != null && localHourlyForecastData.getList().size() > count) {
|
||||
org.openhab.binding.openweathermap.internal.dto.forecast.hourly.List forecastData = localHourlyForecastData
|
||||
.getList().get(count);
|
||||
State state = UnDefType.UNDEF;
|
||||
switch (channelId) {
|
||||
case CHANNEL_TIME_STAMP:
|
||||
state = getDateTimeTypeState(forecastData.getDt());
|
||||
break;
|
||||
case CHANNEL_CONDITION:
|
||||
if (!forecastData.getWeather().isEmpty()) {
|
||||
state = getStringTypeState(forecastData.getWeather().get(0).getDescription());
|
||||
}
|
||||
break;
|
||||
case CHANNEL_CONDITION_ID:
|
||||
if (!forecastData.getWeather().isEmpty()) {
|
||||
state = getStringTypeState(forecastData.getWeather().get(0).getId().toString());
|
||||
}
|
||||
break;
|
||||
case CHANNEL_CONDITION_ICON:
|
||||
if (!forecastData.getWeather().isEmpty()) {
|
||||
state = getRawTypeState(
|
||||
OpenWeatherMapConnection.getWeatherIcon(forecastData.getWeather().get(0).getIcon()));
|
||||
}
|
||||
break;
|
||||
case CHANNEL_CONDITION_ICON_ID:
|
||||
if (!forecastData.getWeather().isEmpty()) {
|
||||
state = getStringTypeState(forecastData.getWeather().get(0).getIcon());
|
||||
}
|
||||
break;
|
||||
case CHANNEL_TEMPERATURE:
|
||||
state = getQuantityTypeState(forecastData.getMain().getTemp(), CELSIUS);
|
||||
break;
|
||||
case CHANNEL_APPARENT_TEMPERATURE:
|
||||
state = getQuantityTypeState(forecastData.getMain().getFeelsLikeTemp(), CELSIUS);
|
||||
break;
|
||||
case CHANNEL_MIN_TEMPERATURE:
|
||||
state = getQuantityTypeState(forecastData.getMain().getTempMin(), CELSIUS);
|
||||
break;
|
||||
case CHANNEL_MAX_TEMPERATURE:
|
||||
state = getQuantityTypeState(forecastData.getMain().getTempMax(), CELSIUS);
|
||||
break;
|
||||
case CHANNEL_PRESSURE:
|
||||
state = getQuantityTypeState(forecastData.getMain().getPressure(), HECTO(PASCAL));
|
||||
break;
|
||||
case CHANNEL_HUMIDITY:
|
||||
state = getQuantityTypeState(forecastData.getMain().getHumidity(), PERCENT);
|
||||
break;
|
||||
case CHANNEL_WIND_SPEED:
|
||||
state = getQuantityTypeState(forecastData.getWind().getSpeed(), METRE_PER_SECOND);
|
||||
break;
|
||||
case CHANNEL_WIND_DIRECTION:
|
||||
state = getQuantityTypeState(forecastData.getWind().getDeg(), DEGREE_ANGLE);
|
||||
break;
|
||||
case CHANNEL_GUST_SPEED:
|
||||
state = getQuantityTypeState(forecastData.getWind().getGust(), METRE_PER_SECOND);
|
||||
break;
|
||||
case CHANNEL_CLOUDINESS:
|
||||
state = getQuantityTypeState(forecastData.getClouds().getAll(), PERCENT);
|
||||
break;
|
||||
case CHANNEL_RAIN:
|
||||
Rain rain = forecastData.getRain();
|
||||
state = getQuantityTypeState(rain == null ? 0 : rain.getVolume(), MILLI(METRE));
|
||||
break;
|
||||
case CHANNEL_SNOW:
|
||||
Snow snow = forecastData.getSnow();
|
||||
state = getQuantityTypeState(snow == null ? 0 : snow.getVolume(), MILLI(METRE));
|
||||
break;
|
||||
}
|
||||
logger.debug("Update channel '{}' of group '{}' with new state '{}'.", channelId, channelGroupId, state);
|
||||
updateState(channelUID, state);
|
||||
} else {
|
||||
logger.debug("No weather data available to update channel '{}' of group '{}'.", channelId, channelGroupId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the channel from the last OpenWeatherMap data retrieved.
|
||||
*
|
||||
* @param channelUID the id identifying the channel to be updated
|
||||
* @param count
|
||||
*/
|
||||
private void updateDailyForecastChannel(ChannelUID channelUID, int count) {
|
||||
String channelId = channelUID.getIdWithoutGroup();
|
||||
String channelGroupId = channelUID.getGroupId();
|
||||
OpenWeatherMapJsonDailyForecastData localDailyForecastData = dailyForecastData;
|
||||
if (localDailyForecastData != null && localDailyForecastData.getList().size() > count) {
|
||||
org.openhab.binding.openweathermap.internal.dto.forecast.daily.List forecastData = localDailyForecastData
|
||||
.getList().get(count);
|
||||
State state = UnDefType.UNDEF;
|
||||
switch (channelId) {
|
||||
case CHANNEL_TIME_STAMP:
|
||||
state = getDateTimeTypeState(forecastData.getDt());
|
||||
break;
|
||||
case CHANNEL_CONDITION:
|
||||
if (!forecastData.getWeather().isEmpty()) {
|
||||
state = getStringTypeState(forecastData.getWeather().get(0).getDescription());
|
||||
}
|
||||
break;
|
||||
case CHANNEL_CONDITION_ID:
|
||||
if (!forecastData.getWeather().isEmpty()) {
|
||||
state = getStringTypeState(forecastData.getWeather().get(0).getId().toString());
|
||||
}
|
||||
break;
|
||||
case CHANNEL_CONDITION_ICON:
|
||||
if (!forecastData.getWeather().isEmpty()) {
|
||||
state = getRawTypeState(
|
||||
OpenWeatherMapConnection.getWeatherIcon(forecastData.getWeather().get(0).getIcon()));
|
||||
}
|
||||
break;
|
||||
case CHANNEL_CONDITION_ICON_ID:
|
||||
if (!forecastData.getWeather().isEmpty()) {
|
||||
state = getStringTypeState(forecastData.getWeather().get(0).getIcon());
|
||||
}
|
||||
break;
|
||||
case CHANNEL_MIN_TEMPERATURE:
|
||||
state = getQuantityTypeState(forecastData.getTemp().getMin(), CELSIUS);
|
||||
break;
|
||||
case CHANNEL_MAX_TEMPERATURE:
|
||||
state = getQuantityTypeState(forecastData.getTemp().getMax(), CELSIUS);
|
||||
break;
|
||||
case CHANNEL_APPARENT_TEMPERATURE:
|
||||
FeelsLikeTemp feelsLikeTemp = forecastData.getFeelsLikeTemp();
|
||||
if (feelsLikeTemp != null) {
|
||||
state = getQuantityTypeState(feelsLikeTemp.getDay(), CELSIUS);
|
||||
}
|
||||
break;
|
||||
case CHANNEL_PRESSURE:
|
||||
state = getQuantityTypeState(forecastData.getPressure(), HECTO(PASCAL));
|
||||
break;
|
||||
case CHANNEL_HUMIDITY:
|
||||
state = getQuantityTypeState(forecastData.getHumidity(), PERCENT);
|
||||
break;
|
||||
case CHANNEL_WIND_SPEED:
|
||||
state = getQuantityTypeState(forecastData.getSpeed(), METRE_PER_SECOND);
|
||||
break;
|
||||
case CHANNEL_WIND_DIRECTION:
|
||||
state = getQuantityTypeState(forecastData.getDeg(), DEGREE_ANGLE);
|
||||
break;
|
||||
case CHANNEL_GUST_SPEED:
|
||||
state = getQuantityTypeState(forecastData.getGust(), METRE_PER_SECOND);
|
||||
break;
|
||||
case CHANNEL_CLOUDINESS:
|
||||
state = getQuantityTypeState(forecastData.getClouds(), PERCENT);
|
||||
break;
|
||||
case CHANNEL_RAIN:
|
||||
Double rain = forecastData.getRain();
|
||||
state = getQuantityTypeState(rain == null ? 0 : rain, MILLI(METRE));
|
||||
break;
|
||||
case CHANNEL_SNOW:
|
||||
Double snow = forecastData.getSnow();
|
||||
state = getQuantityTypeState(snow == null ? 0 : snow, MILLI(METRE));
|
||||
break;
|
||||
}
|
||||
logger.debug("Update channel '{}' of group '{}' with new state '{}'.", channelId, channelGroupId, state);
|
||||
updateState(channelUID, state);
|
||||
} else {
|
||||
logger.debug("No weather data available to update channel '{}' of group '{}'.", channelId, channelGroupId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.openweathermap.internal.utils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.config.core.ConfigConstants;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* This is a simple file based cache implementation.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ByteArrayFileCache {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(ByteArrayFileCache.class);
|
||||
|
||||
private static final String CACHE_FOLDER_NAME = "cache";
|
||||
public static final char EXTENSION_SEPARATOR = '.';
|
||||
|
||||
protected final File cacheFolder;
|
||||
|
||||
public ByteArrayFileCache(String servicePID) {
|
||||
// TODO track and limit folder size
|
||||
// TODO support user specific folder
|
||||
cacheFolder = new File(new File(new File(ConfigConstants.getUserDataFolder()), CACHE_FOLDER_NAME), servicePID);
|
||||
if (!cacheFolder.exists()) {
|
||||
logger.debug("Creating cache folder '{}'", cacheFolder.getAbsolutePath());
|
||||
cacheFolder.mkdirs();
|
||||
}
|
||||
logger.debug("Using cache folder '{}'", cacheFolder.getAbsolutePath());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a file to the cache. If the cache previously contained a file for the key, the old file is replaced by the
|
||||
* new content.
|
||||
*
|
||||
* @param key the key with which the file is to be associated
|
||||
* @param content the content for the file to be associated with the specified key
|
||||
*/
|
||||
public void put(String key, byte[] content) {
|
||||
writeFile(getUniqueFile(key), content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a file to the cache.
|
||||
*
|
||||
* @param key the key with which the file is to be associated
|
||||
* @param content the content for the file to be associated with the specified key
|
||||
*/
|
||||
public void putIfAbsent(String key, byte[] content) {
|
||||
File fileInCache = getUniqueFile(key);
|
||||
if (fileInCache.exists()) {
|
||||
logger.debug("File '{}' present in cache", fileInCache.getName());
|
||||
} else {
|
||||
writeFile(fileInCache, content);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a file to the cache and returns the content of the file.
|
||||
*
|
||||
* @param key the key with which the file is to be associated
|
||||
* @param content the content for the file to be associated with the specified key
|
||||
* @return the content of the file associated with the given key
|
||||
*/
|
||||
public byte[] putIfAbsentAndGet(String key, byte[] content) {
|
||||
putIfAbsent(key, content);
|
||||
|
||||
// return get(key);
|
||||
return content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the given content to the given {@link File}.
|
||||
*
|
||||
* @param fileInCache the {@link File}
|
||||
* @param content the content to be written
|
||||
*/
|
||||
private void writeFile(File fileInCache, byte[] content) {
|
||||
logger.debug("Caching file '{}'", fileInCache.getName());
|
||||
try {
|
||||
Files.write(fileInCache.toPath(), content);
|
||||
} catch (IOException e) {
|
||||
logger.warn("Could not write file '{}' to cache", fileInCache.getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the key is present in the cache.
|
||||
*
|
||||
* @param key the key whose presence in the cache is to be tested
|
||||
* @return true if the cache contains a file for the specified key
|
||||
*/
|
||||
public boolean containsKey(String key) {
|
||||
return getUniqueFile(key).exists();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the file associated with the given key from the cache.
|
||||
*
|
||||
* @param key the key whose associated file is to be removed
|
||||
*/
|
||||
public void remove(String key) {
|
||||
deleteFile(getUniqueFile(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the given {@link File}.
|
||||
*
|
||||
* @param fileInCache the {@link File}
|
||||
*/
|
||||
private void deleteFile(File fileInCache) {
|
||||
if (fileInCache.exists()) {
|
||||
logger.debug("Deleting file '{}' from cache", fileInCache.getName());
|
||||
fileInCache.delete();
|
||||
} else {
|
||||
logger.debug("File '{}' not found in cache", fileInCache.getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all files from the cache.
|
||||
*/
|
||||
public void clear() {
|
||||
File[] filesInCache = cacheFolder.listFiles();
|
||||
if (filesInCache != null && filesInCache.length > 0) {
|
||||
logger.debug("Deleting all files from cache");
|
||||
Arrays.stream(filesInCache).forEach(File::delete);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the content of the file associated with the given key, if it is present.
|
||||
*
|
||||
* @param key the key whose associated file is to be returned
|
||||
* @return the content of the file associated with the given key
|
||||
*/
|
||||
public byte[] get(String key) {
|
||||
return readFile(getUniqueFile(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the content from the given {@link File}, if it is present.
|
||||
*
|
||||
* @param fileInCache the {@link File}
|
||||
* @return the content of the file
|
||||
*/
|
||||
private byte[] readFile(File fileInCache) {
|
||||
if (fileInCache.exists()) {
|
||||
logger.debug("Reading file '{}' from cache", fileInCache.getName());
|
||||
try {
|
||||
return Files.readAllBytes(fileInCache.toPath());
|
||||
} catch (IOException e) {
|
||||
logger.warn("Could not read file '{}' from cache", fileInCache.getName(), e);
|
||||
}
|
||||
} else {
|
||||
logger.debug("File '{}' not found in cache", fileInCache.getName());
|
||||
}
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a unique {@link File} from the key with which the file is to be associated.
|
||||
*
|
||||
* @param key the key with which the file is to be associated
|
||||
* @return unique file for the file associated with the given key
|
||||
*/
|
||||
private File getUniqueFile(String key) {
|
||||
// TODO: store / cache file internally for faster operations
|
||||
String fileExtension = getFileExtension(key);
|
||||
return new File(cacheFolder,
|
||||
getUniqueFileName(key) + (fileExtension == null ? "" : EXTENSION_SEPARATOR + fileExtension));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the extension of a file name.
|
||||
*
|
||||
* @param fileName the file name to retrieve the extension of
|
||||
* @return the extension of the file or null if none exists
|
||||
*/
|
||||
private @Nullable String getFileExtension(String fileName) {
|
||||
int index = fileName.lastIndexOf(EXTENSION_SEPARATOR);
|
||||
// exclude file names starting with a dot
|
||||
if (index > 0) {
|
||||
return fileName.substring(index + 1);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a unique file name from the key with which the file is to be associated.
|
||||
*
|
||||
* @param key the key with which the file is to be associated
|
||||
* @return unique file name for the file associated with the given key
|
||||
*/
|
||||
private String getUniqueFileName(String key) {
|
||||
try {
|
||||
byte[] bytesOfFileName = key.getBytes(StandardCharsets.UTF_8);
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
byte[] md5Hash = md.digest(bytesOfFileName);
|
||||
BigInteger bigInt = new BigInteger(1, md5Hash);
|
||||
StringBuilder fileNameHash = new StringBuilder(bigInt.toString(16));
|
||||
// Now we need to zero pad it if you actually want the full 32 chars
|
||||
while (fileNameHash.length() < 32) {
|
||||
fileNameHash.insert(0, "0");
|
||||
}
|
||||
return fileNameHash.toString();
|
||||
} catch (NoSuchAlgorithmException ex) {
|
||||
// should not happen
|
||||
logger.error("Could not create MD5 hash for key '{}'", key, ex);
|
||||
return key.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding id="openweathermap" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
|
||||
|
||||
<name>OpenWeatherMap Binding</name>
|
||||
<description>OpenWeatherMap - Current weather and forecasts in your city.</description>
|
||||
<author>Christoph Weitkamp</author>
|
||||
|
||||
</binding:binding>
|
||||
@@ -0,0 +1,91 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<config-description:config-descriptions
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:config-description="https://openhab.org/schemas/config-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/config-description/v1.0.0 https://openhab.org/schemas/config-description-1.0.0.xsd">
|
||||
|
||||
<!-- Config for OpenWeatherMap Binding -->
|
||||
<config-description uri="bridge-type:openweathermap:weather-api">
|
||||
<parameter name="apikey" type="text" required="true">
|
||||
<context>password</context>
|
||||
<label>API Key</label>
|
||||
<description>API key to access the OpenWeatherMap API.</description>
|
||||
</parameter>
|
||||
<parameter name="refreshInterval" type="integer" min="10" unit="min">
|
||||
<label>Refresh Interval</label>
|
||||
<description>Specifies the refresh interval (in minutes).</description>
|
||||
<default>60</default>
|
||||
</parameter>
|
||||
<parameter name="language" type="text">
|
||||
<label>Language</label>
|
||||
<description>Language to be used by the OpenWeatherMap API.</description>
|
||||
<options>
|
||||
<option value="ar">Arabic</option>
|
||||
<option value="bg">Bulgarian</option>
|
||||
<option value="ca">Catalan</option>
|
||||
<option value="zh_cn">Chinese - Simplified</option>
|
||||
<option value="zh_tw">Chinese - Traditional</option>
|
||||
<option value="hr">Croatian</option>
|
||||
<option value="cz">Czech</option>
|
||||
<option value="nl">Dutch</option>
|
||||
<option value="en">English</option>
|
||||
<option value="fi">Finnish</option>
|
||||
<option value="fr">French</option>
|
||||
<option value="gl">Galician</option>
|
||||
<option value="de">German</option>
|
||||
<option value="el">Greek</option>
|
||||
<option value="hu">Hungarian</option>
|
||||
<option value="it">Italian</option>
|
||||
<option value="ja">Japanese</option>
|
||||
<option value="kr">Korean</option>
|
||||
<option value="la">Latvian</option>
|
||||
<option value="lt">Lithuanian</option>
|
||||
<option value="mk">Macedonian</option>
|
||||
<option value="fa">Persian (Farsi)</option>
|
||||
<option value="pl">Polish</option>
|
||||
<option value="pt">Portuguese</option>
|
||||
<option value="ro">Romanian</option>
|
||||
<option value="ru">Russian</option>
|
||||
<option value="sk">Slovak</option>
|
||||
<option value="se">Swedish</option>
|
||||
<option value="sl">Slovenian</option>
|
||||
<option value="es">Spanish</option>
|
||||
<option value="tr">Turkish</option>
|
||||
<option value="ua">Ukrainian</option>
|
||||
<option value="vi">Vietnamese</option>
|
||||
</options>
|
||||
</parameter>
|
||||
</config-description>
|
||||
|
||||
<config-description uri="thing-type:openweathermap:weather-and-forecast">
|
||||
<parameter name="location" type="text" required="true">
|
||||
<context>location</context>
|
||||
<label>Location of Weather</label>
|
||||
<description>Location of weather in geographical coordinates (latitude/longitude/altitude).</description>
|
||||
</parameter>
|
||||
<parameter name="forecastHours" type="integer" min="0" max="120" step="3">
|
||||
<label>Number of Hours</label>
|
||||
<description>Number of hours for hourly forecast.</description>
|
||||
<default>24</default>
|
||||
</parameter>
|
||||
<parameter name="forecastDays" type="integer" min="0" max="16" step="1">
|
||||
<label>Number of Days</label>
|
||||
<description>Number of days for daily forecast.</description>
|
||||
<default>6</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
|
||||
<config-description uri="thing-type:openweathermap:uvindex">
|
||||
<parameter name="location" type="text" required="true">
|
||||
<context>location</context>
|
||||
<label>Location of Weather</label>
|
||||
<description>Location of weather in geographical coordinates (latitude/longitude/altitude).</description>
|
||||
</parameter>
|
||||
<parameter name="forecastDays" type="integer" min="1" max="8" step="1">
|
||||
<label>Number of Days</label>
|
||||
<description>Number of days for UV Index forecast.</description>
|
||||
<default>6</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
|
||||
</config-description:config-descriptions>
|
||||
@@ -0,0 +1,15 @@
|
||||
# thing status
|
||||
offline.conf-error-missing-apikey = The 'apikey' parameter must be configured.
|
||||
offline.conf-error-invalid-apikey = Invalid API key. Please see https://openweathermap.org/faq#error401 for more info.
|
||||
offline.conf-error-not-supported-refreshInterval = The 'refreshInterval' parameter must be at least 10 minutes.
|
||||
offline.conf-error-not-supported-language = The given 'language' parameter is not supported.
|
||||
|
||||
offline.conf-error-missing-location = The 'location' parameter must be configured.
|
||||
offline.conf-error-parsing-location = The 'location' parameter could not be split into latitude and longitude.
|
||||
offline.conf-error-not-supported-number-of-hours = The 'forecastHours' parameter must be between 0 and 120 - increment 3.
|
||||
offline.conf-error-not-supported-number-of-days = The 'forecastDays' parameter must be between 0 and 16.
|
||||
offline.conf-error-not-supported-uvindex-number-of-days = The 'forecastDays' parameter must be between 1 and 8.
|
||||
|
||||
# discovery result
|
||||
discovery.openweathermap.weather-and-forecast.api.local.label = Local Weather And Forecast
|
||||
discovery.openweathermap.uvindex.api.local.label = Local UV Index
|
||||
@@ -0,0 +1,263 @@
|
||||
# binding
|
||||
binding.openweathermap.name = OpenWeatherMap Binding
|
||||
binding.openweathermap.description = OpenWeatherMap - Aktuelles Wetter und Prognosen in Ihrer Stadt.
|
||||
|
||||
# bridge types
|
||||
thing-type.openweathermap.weather-api.label = OpenWeatherMap Konto
|
||||
thing-type.openweathermap.weather-api.description = Ermöglicht den Zugriff auf die OpenWeatherMap API.
|
||||
|
||||
# bridge types config
|
||||
bridge-type.config.openweathermap.weather-api.apikey.label = API Schlüssel
|
||||
bridge-type.config.openweathermap.weather-api.apikey.description = API Schlüssel für den Zugriff auf die OpenWeatherMap API.
|
||||
|
||||
bridge-type.config.openweathermap.weather-api.refreshInterval.label = Abfrageintervall
|
||||
bridge-type.config.openweathermap.weather-api.refreshInterval.description = Intervall zur Abfrage der OpenWeatherMap API (in min).
|
||||
|
||||
bridge-type.config.openweathermap.weather-api.language.label = Sprache
|
||||
bridge-type.config.openweathermap.weather-api.language.description = Sprache zur Anzeige der Daten.
|
||||
bridge-type.config.openweathermap.weather-api.language.option.ar = Arabisch
|
||||
bridge-type.config.openweathermap.weather-api.language.option.bg = Bulgarisch
|
||||
bridge-type.config.openweathermap.weather-api.language.option.ca = Katalanisch
|
||||
bridge-type.config.openweathermap.weather-api.language.option.cz = Tschechisch
|
||||
bridge-type.config.openweathermap.weather-api.language.option.de = Deutsch
|
||||
bridge-type.config.openweathermap.weather-api.language.option.el = Griechisch
|
||||
bridge-type.config.openweathermap.weather-api.language.option.en = Englisch
|
||||
bridge-type.config.openweathermap.weather-api.language.option.es = Spanisch
|
||||
bridge-type.config.openweathermap.weather-api.language.option.fa = Persisch (Farsi)
|
||||
bridge-type.config.openweathermap.weather-api.language.option.fi = Finnisch
|
||||
bridge-type.config.openweathermap.weather-api.language.option.fr = Französisch
|
||||
bridge-type.config.openweathermap.weather-api.language.option.gl = Galizisch
|
||||
bridge-type.config.openweathermap.weather-api.language.option.hr = Kroatisch
|
||||
bridge-type.config.openweathermap.weather-api.language.option.hu = Ungarisch
|
||||
bridge-type.config.openweathermap.weather-api.language.option.it = Italienisch
|
||||
bridge-type.config.openweathermap.weather-api.language.option.ja = Japanisch
|
||||
bridge-type.config.openweathermap.weather-api.language.option.kr = Koreanisch
|
||||
bridge-type.config.openweathermap.weather-api.language.option.la = Lettisch
|
||||
bridge-type.config.openweathermap.weather-api.language.option.lt = Litauisch
|
||||
bridge-type.config.openweathermap.weather-api.language.option.mk = Mazedonisch
|
||||
bridge-type.config.openweathermap.weather-api.language.option.nl = Holländisch
|
||||
bridge-type.config.openweathermap.weather-api.language.option.pl = Polnisch
|
||||
bridge-type.config.openweathermap.weather-api.language.option.pt = Portugiesisch
|
||||
bridge-type.config.openweathermap.weather-api.language.option.ro = Rumänisch
|
||||
bridge-type.config.openweathermap.weather-api.language.option.ru = Russisch
|
||||
bridge-type.config.openweathermap.weather-api.language.option.se = Schwedisch
|
||||
bridge-type.config.openweathermap.weather-api.language.option.sk = Slowakisch
|
||||
bridge-type.config.openweathermap.weather-api.language.option.sl = Slowenisch
|
||||
bridge-type.config.openweathermap.weather-api.language.option.tr = Türkisch
|
||||
bridge-type.config.openweathermap.weather-api.language.option.ua = Ukrainisch
|
||||
bridge-type.config.openweathermap.weather-api.language.option.vi = Vietnamesisch
|
||||
bridge-type.config.openweathermap.weather-api.language.option.zh_cn = Chinesisch - Simplified
|
||||
bridge-type.config.openweathermap.weather-api.language.option.zh_tw = Chinesisch - Traditional
|
||||
|
||||
# thing types
|
||||
thing-type.openweathermap.weather-and-forecast.label = Wetterinformationen
|
||||
thing-type.openweathermap.weather-and-forecast.description = Ermöglicht die Anzeige der aktuellen Wetterinformationen und der Wettervorhersage.
|
||||
|
||||
thing-type.openweathermap.uvindex.label = UV-Index
|
||||
thing-type.openweathermap.uvindex.description = Ermöglicht die Anzeige des aktuellen UV-Index.
|
||||
|
||||
# thing types config
|
||||
thing-type.config.openweathermap.weather-and-forecast.location.label = Ort der Wetterdaten
|
||||
thing-type.config.openweathermap.weather-and-forecast.location.description = Ort der Wetterdaten in geographischen Koordinaten (Breitengrad/Längengrad/Höhe).
|
||||
|
||||
thing-type.config.openweathermap.weather-and-forecast.forecastHours.label = Stunden
|
||||
thing-type.config.openweathermap.weather-and-forecast.forecastHours.description = Anzahl der Stunden für die Wettervorhersage.
|
||||
|
||||
thing-type.config.openweathermap.weather-and-forecast.forecastDays.label = Tage
|
||||
thing-type.config.openweathermap.weather-and-forecast.forecastDays.description = Anzahl der Tage für die Wettervorhersage.
|
||||
|
||||
thing-type.config.openweathermap.uvindex.location.label = Ort der Wetterdaten
|
||||
thing-type.config.openweathermap.uvindex.location.description = Ort der Wetterdaten in geographischen Koordinaten (Breitengrad/Längengrad/Höhe).
|
||||
|
||||
thing-type.config.openweathermap.uvindex.forecastDays.label = Tage
|
||||
thing-type.config.openweathermap.uvindex.forecastDays.description = Anzahl der Tage für die UV-Index Vorhersage.
|
||||
|
||||
# channel group types
|
||||
channel-group-type.openweathermap.station.label = Wetterstation
|
||||
channel-group-type.openweathermap.station.description = Fasst Daten über die Wetterstation oder den Ort zusammen.
|
||||
|
||||
channel-group-type.openweathermap.weather.label = Aktuelles Wetter
|
||||
channel-group-type.openweathermap.weather.description = Fasst aktuelle Wetterdaten zusammen.
|
||||
|
||||
channel-group-type.openweathermap.hourlyForecast.label = 3 Stunden Wettervorhersage
|
||||
channel-group-type.openweathermap.hourlyForecast.description = Fasst Daten der 5 Tage / 3 Stunden Wettervorhersage zusammen.
|
||||
|
||||
channel-group-type.openweathermap.dailyForecast.label = Tägliche Wettervorhersage
|
||||
channel-group-type.openweathermap.dailyForecast.description = Fasst Daten der 16 Tage / täglichen Wettervorhersage zusammen.
|
||||
|
||||
channel-group-type.openweathermap.uvindex.label = Aktueller UV-Index
|
||||
channel-group-type.openweathermap.uvindex.description = Fasst aktuelle UV-Index Daten zusammen.
|
||||
|
||||
channel-group-type.openweathermap.uvindexForecast.label = UV-Index Vorhersage
|
||||
channel-group-type.openweathermap.uvindexForecast.description = Fasst Daten der UV-Index Vorhersage zusammen.
|
||||
|
||||
# channel groups
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastHours03.label = Wettervorhersage für 3 Stunden
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastHours03.description = Fasst Daten der Wettervorhersage in den nächsten drei Stunden zusammen.
|
||||
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastHours06.label = Wettervorhersage für 6 Stunden
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastHours06.description = Fasst Daten der Wettervorhersage in sechs Stunden zusammen.
|
||||
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastHours09.label = Wettervorhersage für 9 Stunden
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastHours09.description = Fasst Daten der Wettervorhersage in neun Stunden zusammen.
|
||||
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastHours12.label = Wettervorhersage für 12 Stunden
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastHours12.description = Fasst Daten der Wettervorhersage in zwölf Stunden zusammen.
|
||||
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastHours15.label = Wettervorhersage für 15 Stunden
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastHours15.description = Fasst Daten der Wettervorhersage in 15 Stunden zusammen.
|
||||
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastHours18.label = Wettervorhersage für 18 Stunden
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastHours18.description = Fasst Daten der Wettervorhersage in 18 Stunden zusammen.
|
||||
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastHours21.label = Wettervorhersage für 21 Stunden
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastHours21.description = Fasst Daten der Wettervorhersage in 21 Stunden zusammen.
|
||||
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastHours24.label = Wettervorhersage für 24 Stunden
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastHours24.description = Fasst Daten der Wettervorhersage in 24 Stunden zusammen.
|
||||
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastToday.label = Wettervorhersage für heute
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastToday.description = Fasst Daten der heutigen Wettervorhersage zusammen.
|
||||
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastTomorrow.label = Wettervorhersage für morgen
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastTomorrow.description = Fasst Daten der morgigen Wettervorhersage zusammen.
|
||||
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastDay2.label = Wettervorhersage für übermorgen
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastDay2.description = Fasst Daten der übermorgigen Wettervorhersage zusammen.
|
||||
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastDay3.label = Wettervorhersage für 3 Tage
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastDay3.description = Fasst Daten der Wettervorhersage in drei Tagen zusammen.
|
||||
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastDay4.label = Wettervorhersage für 4 Tage
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastDay4.description = Fasst Daten der Wettervorhersage in vier Tagen zusammen.
|
||||
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastDay5.label = Wettervorhersage für 5 Tage
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastDay5.description = Fasst Daten der Wettervorhersage in fünf Tagen zusammen.
|
||||
|
||||
thing-type.openweathermap.uvindex.group.forecastTomorrow.label = UV-Index für morgen
|
||||
thing-type.openweathermap.uvindex.group.forecastTomorrow.description = Fasst Daten der morgigen UV-Index Vorhersage zusammen.
|
||||
|
||||
thing-type.openweathermap.uvindex.group.forecastDay2.label = UV-Index für übermorgen
|
||||
thing-type.openweathermap.uvindex.group.forecastDay2.description = Fasst Daten der übermorgigen UV-Index Vorhersage zusammen.
|
||||
|
||||
thing-type.openweathermap.uvindex.group.forecastDay3.label = UV-Index für 3 Tage
|
||||
thing-type.openweathermap.uvindex.group.forecastDay3.description = Fasst Daten der UV-Index Vorhersage in drei Tagen zusammen.
|
||||
|
||||
thing-type.openweathermap.uvindex.group.forecastDay4.label = UV-Index für 4 Tage
|
||||
thing-type.openweathermap.uvindex.group.forecastDay4.description = Fasst Daten der UV-Index Vorhersage in vier Tagen zusammen.
|
||||
|
||||
thing-type.openweathermap.uvindex.group.forecastDay5.label = UV-Index für 5 Tage
|
||||
thing-type.openweathermap.uvindex.group.forecastDay5.description = Fasst Daten der UV-Index Vorhersage in fünf Tagen zusammen.
|
||||
|
||||
# channel types
|
||||
channel-type.openweathermap.station-id.label = Station-ID
|
||||
channel-type.openweathermap.station-id.description = Zeigt die ID der Wetterstation oder des Ortes an.
|
||||
|
||||
channel-type.openweathermap.station-name.label = Name
|
||||
channel-type.openweathermap.station-name.description = Zeigt den Namen der Wetterstation oder des Ortes an.
|
||||
|
||||
channel-group-type.openweathermap.station.channel.location.label = Ort
|
||||
channel-group-type.openweathermap.station.channel.location.description = Zeigt den Ort der Wetterstation in geographischen Koordinaten (Breitengrad/Längengrad/Höhe) an.
|
||||
|
||||
channel-type.openweathermap.time-stamp.label = Letzte Messung
|
||||
channel-type.openweathermap.time-stamp.description = Zeigt den Zeitpunkt der letzten Messung an.
|
||||
channel-type.openweathermap.time-stamp.state.pattern = %1$td.%1$tm.%1$tY %1$tH:%1$tM:%1$tS
|
||||
|
||||
channel-type.openweathermap.hourly-forecast-time-stamp.label = Vorhersage Zeit
|
||||
channel-type.openweathermap.hourly-forecast-time-stamp.description = Zeigt den Zeitpunkt der Vorhersage an.
|
||||
channel-type.openweathermap.hourly-forecast-time-stamp.state.pattern = %1$td.%1$tm.%1$tY %1$tH:%1$tM:%1$tS
|
||||
|
||||
channel-type.openweathermap.daily-forecast-time-stamp.label = Vorhersage Datum
|
||||
channel-type.openweathermap.daily-forecast-time-stamp.description = Zeigt das Datum der Vorhersage an.
|
||||
channel-type.openweathermap.daily-forecast-time-stamp.state.pattern = %1$td.%1$tm.%1$tY
|
||||
|
||||
channel-type.openweathermap.condition.label = Wetterlage
|
||||
channel-type.openweathermap.condition.description = Zeigt die aktuelle Wetterlage an.
|
||||
|
||||
channel-type.openweathermap.forecasted-condition.label = Vorhergesagte Wetterlage
|
||||
channel-type.openweathermap.forecasted-condition.description = Zeigt die vorhergesagte Wetterlage an.
|
||||
|
||||
channel-type.openweathermap.condition-id.label = Wetterlage-ID
|
||||
channel-type.openweathermap.condition-id.description = Zeigt die ID der Wetterlage an.
|
||||
|
||||
channel-type.openweathermap.condition-icon.label = Icon
|
||||
channel-type.openweathermap.condition-icon.description = Zeigt das Icon der Wetterlage an.
|
||||
|
||||
channel-type.openweathermap.condition-icon-id.label = Icon-ID
|
||||
channel-type.openweathermap.condition-icon-id.description = Zeigt die ID für das Icon der Wetterlage an.
|
||||
|
||||
channel-type.openweathermap.forecasted-outdoor-temperature.label = Vorhergesagte Temperatur
|
||||
channel-type.openweathermap.forecasted-outdoor-temperature.description = Zeigt die vorhergesagte Außentemperatur an.
|
||||
|
||||
channel-type.openweathermap.forecasted-min-outdoor-temperature.label = Minimale Temperatur
|
||||
channel-type.openweathermap.forecasted-min-outdoor-temperature.description = Zeigt die vorhergesagte minimale Außentemperatur an.
|
||||
|
||||
channel-type.openweathermap.forecasted-max-outdoor-temperature.label = Maximale Temperatur
|
||||
channel-type.openweathermap.forecasted-max-outdoor-temperature.description = Zeigt die vorhergesagte maximale Außentemperatur an.
|
||||
|
||||
channel-type.openweathermap.apparent-temperature.label = Gefühlte Temperatur
|
||||
channel-type.openweathermap.apparent-temperature.description = Zeigt die gefühlte Außentemperatur an.
|
||||
|
||||
channel-type.openweathermap.forecasted-apparent-temperature.label = Vorhergesagte Gefühlte Temperatur
|
||||
channel-type.openweathermap.forecasted-apparent-temperature.description = Zeigt die vorhergesagte gefühlte Außentemperatur an.
|
||||
|
||||
channel-type.openweathermap.forecasted-barometric-pressure.label = Vorhergesagter Luftdruck
|
||||
channel-type.openweathermap.forecasted-barometric-pressure.description = Zeigt den vorhergesagten Luftdruck an.
|
||||
|
||||
channel-type.openweathermap.forecasted-atmospheric-humidity.label = Vorhergesagte Luftfeuchtigkeit
|
||||
channel-type.openweathermap.forecasted-atmospheric-humidity.description = Zeigt die vorhergesagte Luftfeuchtigkeit an.
|
||||
|
||||
channel-type.openweathermap.forecasted-wind-speed.label = Vorhergesagte Windgeschwindigkeit
|
||||
channel-type.openweathermap.forecasted-wind-speed.description = Zeigt die vorhergesagte Windgeschwindigkeit an.
|
||||
|
||||
channel-type.openweathermap.forecasted-wind-direction.label = Vorhergesagte Windrichtung
|
||||
channel-type.openweathermap.forecasted-wind-direction.description = Zeigt die vorhergesagte Windrichtung an.
|
||||
|
||||
channel-type.openweathermap.gust-speed.label = Windböengeschwindigkeit
|
||||
channel-type.openweathermap.gust-speed.description = Zeigt die aktuelle Windböengeschwindigkeit an.
|
||||
|
||||
channel-type.openweathermap.forecasted-gust-speed.label = Vorhergesagte Windböengeschwindigkeit
|
||||
channel-type.openweathermap.forecasted-gust-speed.description = Zeigt die vorhergesagte Windböengeschwindigkeit an.
|
||||
|
||||
channel-type.openweathermap.cloudiness.label = Bewölkung
|
||||
channel-type.openweathermap.cloudiness.description = Zeigt die aktuelle Bewölkung an.
|
||||
|
||||
channel-type.openweathermap.forecasted-cloudiness.label = Vorhergesagte Bewölkung
|
||||
channel-type.openweathermap.forecasted-cloudiness.description = Zeigt die vorhergesagte Bewölkung an.
|
||||
|
||||
channel-type.openweathermap.visibility.label = Sichtweite
|
||||
channel-type.openweathermap.visibility.description = Zeigt die aktuelle Sichtweite an.
|
||||
|
||||
channel-type.openweathermap.rain.label = Regen
|
||||
channel-type.openweathermap.rain.description = Zeigt den kumulierten Regen der letzten Stunde an.
|
||||
|
||||
channel-type.openweathermap.forecasted-rain.label = Vorhergesagter Regen
|
||||
channel-type.openweathermap.forecasted-rain.description = Zeigt die vorhergesagte Regenmenge an.
|
||||
|
||||
channel-type.openweathermap.snow.label = Schnee
|
||||
channel-type.openweathermap.snow.description = Zeigt den kumulierten Schnee der letzten Stunde an.
|
||||
|
||||
channel-type.openweathermap.forecasted-snow.label = Vorhergesagter Schnee
|
||||
channel-type.openweathermap.forecasted-snow.description = Zeigt die vorhergesagte Schneemenge an.
|
||||
|
||||
channel-type.openweathermap.uvindex.label = UV-Index
|
||||
channel-type.openweathermap.uvindex.description = Zeigt den aktuellen UV-Index an.
|
||||
|
||||
channel-type.openweathermap.forecasted-uvindex.label = Vorhergesagter UV-Index
|
||||
channel-type.openweathermap.forecasted-uvindex.description = Zeigt den vorhergesagten UV-Index an.
|
||||
|
||||
# thing status
|
||||
offline.conf-error-missing-apikey = Der Parameter 'API Schlüssel' muss konfiguriert werden.
|
||||
offline.conf-error-invalid-apikey = Ungültiger 'API Schlüssel'. Mehr Infos unter https://openweathermap.org/faq#error401.
|
||||
offline.conf-error-not-supported-refreshInterval = Der Parameter 'Abfrageintervall' muss mindestens 10 min betragen.
|
||||
offline.conf-error-not-supported-language = Der angegebene Parameter 'Sprache' wird nicht unterstützt.
|
||||
|
||||
offline.conf-error-missing-location = Der Parameter 'Ort' muss konfiguriert werden.
|
||||
offline.conf-error-parsing-location = Der Parameter 'Ort' kann nicht in Latitude und Longitude getrennt werden.
|
||||
offline.conf-error-not-supported-number-of-hours = Der Parameter 'forecastHours' muss zwischen 0 und 120 liegen - Schrittweite: 3.
|
||||
offline.conf-error-not-supported-number-of-days = Der Parameter 'forecastDays' muss zwischen 0 und 16 liegen.
|
||||
offline.conf-error-not-supported-uvindex-number-of-days = Der Parameter 'forecastDays' muss zwischen 1 und 8 liegen.
|
||||
|
||||
# discovery result
|
||||
discovery.openweathermap.weather-and-forecast.api.local.label = Lokales Wetter und Wettervorhersage
|
||||
discovery.openweathermap.uvindex.api.local.label = Lokaler UV-Index
|
||||
@@ -0,0 +1,257 @@
|
||||
# binding
|
||||
binding.openweathermap.name = Extension OpenWeatherMap
|
||||
binding.openweathermap.description = L'extension OpenWeatherMap fournit la météo actuelle et les prévisions dans votre ville.
|
||||
|
||||
# bridge types
|
||||
thing-type.openweathermap.weather-api.label = Compte OpenWeatherMap
|
||||
thing-type.openweathermap.weather-api.description = Fournit un accès à l'API d'OpenWeatherMap.
|
||||
|
||||
# bridge types config
|
||||
bridge-type.config.openweathermap.weather-api.apikey.label = Clé API
|
||||
bridge-type.config.openweathermap.weather-api.apikey.description = Clé pour accéder à l'API d'OpenWeatherMap.
|
||||
|
||||
bridge-type.config.openweathermap.weather-api.refreshInterval.label = Intervalle d'actualisation
|
||||
bridge-type.config.openweathermap.weather-api.refreshInterval.description = Spécifie l'intervalle d'actualisation (en minutes).
|
||||
|
||||
bridge-type.config.openweathermap.weather-api.language.label = Langue
|
||||
bridge-type.config.openweathermap.weather-api.language.description = Langue à utiliser par l'API d'OpenWeatherMap.
|
||||
bridge-type.config.openweathermap.weather-api.language.option.ar = Arabe
|
||||
bridge-type.config.openweathermap.weather-api.language.option.bg = Bulgare
|
||||
bridge-type.config.openweathermap.weather-api.language.option.ca = Catalan
|
||||
bridge-type.config.openweathermap.weather-api.language.option.cz = Tchèque
|
||||
bridge-type.config.openweathermap.weather-api.language.option.de = Allemand
|
||||
bridge-type.config.openweathermap.weather-api.language.option.el = Grec
|
||||
bridge-type.config.openweathermap.weather-api.language.option.en = Anglais
|
||||
bridge-type.config.openweathermap.weather-api.language.option.es = Espagnol
|
||||
bridge-type.config.openweathermap.weather-api.language.option.fa = Persan (Farsi)
|
||||
bridge-type.config.openweathermap.weather-api.language.option.fi = Finlandais
|
||||
bridge-type.config.openweathermap.weather-api.language.option.fr = Français
|
||||
bridge-type.config.openweathermap.weather-api.language.option.gl = Galicien
|
||||
bridge-type.config.openweathermap.weather-api.language.option.hr = Croate
|
||||
bridge-type.config.openweathermap.weather-api.language.option.hu = Hongrois
|
||||
bridge-type.config.openweathermap.weather-api.language.option.it = Italien
|
||||
bridge-type.config.openweathermap.weather-api.language.option.ja = Japonais
|
||||
bridge-type.config.openweathermap.weather-api.language.option.kr = Coréen
|
||||
bridge-type.config.openweathermap.weather-api.language.option.la = Letton
|
||||
bridge-type.config.openweathermap.weather-api.language.option.lt = Lituanien
|
||||
bridge-type.config.openweathermap.weather-api.language.option.mk = Macédonien
|
||||
bridge-type.config.openweathermap.weather-api.language.option.nl = Néerlandais
|
||||
bridge-type.config.openweathermap.weather-api.language.option.pl = Polonais
|
||||
bridge-type.config.openweathermap.weather-api.language.option.pt = Portugais
|
||||
bridge-type.config.openweathermap.weather-api.language.option.ro = Roumain
|
||||
bridge-type.config.openweathermap.weather-api.language.option.ru = Russe
|
||||
bridge-type.config.openweathermap.weather-api.language.option.se = Suédois
|
||||
bridge-type.config.openweathermap.weather-api.language.option.sk = Slovaque
|
||||
bridge-type.config.openweathermap.weather-api.language.option.sl = Slovène
|
||||
bridge-type.config.openweathermap.weather-api.language.option.tr = Turc
|
||||
bridge-type.config.openweathermap.weather-api.language.option.ua = Ukrainien
|
||||
bridge-type.config.openweathermap.weather-api.language.option.vi = Vietnamien
|
||||
bridge-type.config.openweathermap.weather-api.language.option.zh_cn = Chinois - Simplifié
|
||||
bridge-type.config.openweathermap.weather-api.language.option.zh_tw = Chinois - Traditionnel
|
||||
|
||||
# thing types
|
||||
thing-type.openweathermap.weather-and-forecast.label = Météo actuelle et prévisions
|
||||
thing-type.openweathermap.weather-and-forecast.description = Fournit les données météorologiques actuelles et les prévisions de l'API d'OpenWeatherMap.
|
||||
|
||||
thing-type.openweathermap.uvindex.label = Indice UV
|
||||
thing-type.openweathermap.uvindex.description = Fournit les données d'indice UV de l'API d'OpenWeatherMap.
|
||||
|
||||
# thing types config
|
||||
thing-type.config.openweathermap.weather-and-forecast.location.label = Localisation
|
||||
thing-type.config.openweathermap.weather-and-forecast.location.description = Localisation en coordonnées géographiques (latitude, longitude, altitude).
|
||||
|
||||
thing-type.config.openweathermap.weather-and-forecast.forecastHours.label = Nombre d'heures
|
||||
thing-type.config.openweathermap.weather-and-forecast.forecastHours.description = Nombre d'heures pour les prévisions horaires.
|
||||
|
||||
thing-type.config.openweathermap.weather-and-forecast.forecastDays.label = Nombre de jours
|
||||
thing-type.config.openweathermap.weather-and-forecast.forecastDays.description = Nombre de jours pour les prévisions quotidiennes.
|
||||
|
||||
thing-type.config.openweathermap.uvindex.location.label = Localisation
|
||||
thing-type.config.openweathermap.uvindex.location.description = Localisation en coordonnées géographiques (latitude, longitude, altitude).
|
||||
|
||||
thing-type.config.openweathermap.uvindex.forecastDays.label = Nombre de jours
|
||||
thing-type.config.openweathermap.uvindex.forecastDays.description = Nombre de jours pour les prévisions d'indice UV.
|
||||
|
||||
# channel group types
|
||||
channel-group-type.openweathermap.station.label = Station météo
|
||||
channel-group-type.openweathermap.station.description = Représente une station météo.
|
||||
|
||||
channel-group-type.openweathermap.weather.label = Météo actuelle
|
||||
channel-group-type.openweathermap.weather.description = Représente la météo actuelle.
|
||||
|
||||
channel-group-type.openweathermap.hourlyForecast.label = Prévisions à 3 heures
|
||||
channel-group-type.openweathermap.hourlyForecast.description = Prévisions météorologiques à 5 jours par tranches de 3 heures.
|
||||
|
||||
channel-group-type.openweathermap.dailyForecast.label = Prévisions quotidiennes
|
||||
channel-group-type.openweathermap.dailyForecast.description = Prévisions météorologiques quotidiennes à 16 jours.
|
||||
|
||||
channel-group-type.openweathermap.uvindex.label = Indice UV actuel
|
||||
channel-group-type.openweathermap.uvindex.description = Représente l'indice UV actuel.
|
||||
|
||||
channel-group-type.openweathermap.uvindexForecast.label = Indice UV pour aujourd'hui
|
||||
channel-group-type.openweathermap.uvindexForecast.description = Représente les prévisions l'indice UV pour aujourd'hui.
|
||||
|
||||
# channel groups
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastHours03.label = Prévisions dans 3 heures
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastHours03.description = Représente les prévisions météorologiques pour les 3 prochaines heures.
|
||||
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastHours06.label = Prévisions dans 6 heures
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastHours06.description = Représente les prévisions météorologiques dans 6 heures.
|
||||
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastHours09.label = Prévisions dans 9 heures
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastHours09.description = Représente les prévisions météorologiques dans 9 heures.
|
||||
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastHours12.label = Prévisions dans 12 heures
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastHours12.description = Représente les prévisions météorologiques dans 12 heures.
|
||||
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastHours15.label = Prévisions dans 15 heures
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastHours15.description = Représente les prévisions météorologiques dans 15 heures.
|
||||
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastHours18.label = Prévisions dans 18 heures
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastHours18.description = Représente les prévisions météorologiques dans 18 heures.
|
||||
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastHours21.label = Prévisions dans 21 heures
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastHours21.description = Représente les prévisions météorologiques dans 21 heures.
|
||||
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastHours24.label = Prévisions dans 24 heures
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastHours24.description = Représente les prévisions météorologiques dans 24 heures.
|
||||
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastToday.label = Prévisions pour aujourd'hui
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastToday.description = Représente les prévisions météorologiques pour aujourd'hui.
|
||||
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastTomorrow.label = Prévisions pour demain
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastTomorrow.description = Représente les prévisions météorologiques pour demain.
|
||||
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastDay2.label = Prévisions dans 2 jours
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastDay2.description = Représente les prévisions météorologiques dans deux jours.
|
||||
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastDay3.label = Prévisions dans 3 jours
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastDay3.description = Représente les prévisions météorologiques dans trois jours.
|
||||
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastDay4.label = Prévisions dans 4 jours
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastDay4.description = Représente les prévisions météorologiques dans quatre jours.
|
||||
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastDay5.label = Prévisions dans 5 jours
|
||||
thing-type.openweathermap.weather-and-forecast.group.forecastDay5.description = Représente les prévisions météorologiques dans cinq jours.
|
||||
|
||||
thing-type.openweathermap.uvindex.group.forecastTomorrow.label = Indice UV pour demain
|
||||
thing-type.openweathermap.uvindex.group.forecastTomorrow.description = Représente les prévisions l'indice UV pour demain.
|
||||
|
||||
thing-type.openweathermap.uvindex.group.forecastDay2.label = Indice UV dans 2 jours
|
||||
thing-type.openweathermap.uvindex.group.forecastDay2.description = Représente les prévisions l'indice UV dans deux jours.
|
||||
|
||||
thing-type.openweathermap.uvindex.group.forecastDay3.label = Indice UV dans 3 jours
|
||||
thing-type.openweathermap.uvindex.group.forecastDay3.description = Représente les prévisions l'indice UV dans trois jours.
|
||||
|
||||
thing-type.openweathermap.uvindex.group.forecastDay4.label = Indice UV dans 4 jours
|
||||
thing-type.openweathermap.uvindex.group.forecastDay4.description = Représente les prévisions l'indice UV dans quatre jours.
|
||||
|
||||
thing-type.openweathermap.uvindex.group.forecastDay5.label = Indice UV dans 5 jours
|
||||
thing-type.openweathermap.uvindex.group.forecastDay5.description = Représente les prévisions l'indice UV dans cinq jours.
|
||||
|
||||
# channel types
|
||||
channel-type.openweathermap.station-id.label = Id station
|
||||
channel-type.openweathermap.station-id.description = L'identifiant de la station météo ou de la ville.
|
||||
|
||||
channel-type.openweathermap.station-name.label = Nom station
|
||||
channel-type.openweathermap.station-name.description = Le nom de la station météo ou de la ville.
|
||||
|
||||
channel-group-type.openweathermap.station.channel.location.label = Localisation
|
||||
channel-group-type.openweathermap.station.channel.location.description = L'emplacement de la station météo ou de la ville en coordonnées géographiques (latitude / longitude / altitude).
|
||||
|
||||
channel-type.openweathermap.time-stamp.label = Heure d'observation
|
||||
channel-type.openweathermap.time-stamp.description = La date et l'heure d'observation de la météo.
|
||||
channel-type.openweathermap.time-stamp.state.pattern = %1$td/%1$tm/%1$tY %1$tH:%1$tM:%1$tS
|
||||
|
||||
channel-type.openweathermap.hourly-forecast-time-stamp.label = Heure des prévisions
|
||||
channel-type.openweathermap.hourly-forecast-time-stamp.description = La date et l'heure des prévisions.
|
||||
channel-type.openweathermap.hourly-forecast-time-stamp.state.pattern = %1$td/%1$tm/%1$tY %1$tH:%1$tM:%1$tS
|
||||
|
||||
channel-type.openweathermap.daily-forecast-time-stamp.label = Date des prévisions
|
||||
channel-type.openweathermap.daily-forecast-time-stamp.description = La date des prévisions.
|
||||
channel-type.openweathermap.daily-forecast-time-stamp.state.pattern = %1$td/%1$tm/%1$tY
|
||||
|
||||
channel-type.openweathermap.condition.label = Conditions météorologiques
|
||||
channel-type.openweathermap.condition.description = Les conditions météorologiques actuelles.
|
||||
|
||||
channel-type.openweathermap.forecasted-condition.label = Conditions météorologiques prévues
|
||||
channel-type.openweathermap.forecasted-condition.description = Les conditions météorologiques prévues.
|
||||
|
||||
channel-type.openweathermap.condition-id.label = Id conditions météorologiques
|
||||
channel-type.openweathermap.condition-id.description = L'identifiant des conditions météorologiques.
|
||||
|
||||
channel-type.openweathermap.condition-icon.label = Icône
|
||||
channel-type.openweathermap.condition-icon.description = L'icône représentant les conditions météorologiques.
|
||||
|
||||
channel-type.openweathermap.condition-icon-id.label = Id icône
|
||||
channel-type.openweathermap.condition-icon-id.description = L'identifiant de l'icône représentant les conditions météorologiques.
|
||||
|
||||
channel-type.openweathermap.forecasted-outdoor-temperature.label = Température prévue
|
||||
channel-type.openweathermap.forecasted-outdoor-temperature.description = La température extérieure prévue.
|
||||
|
||||
channel-type.openweathermap.forecasted-min-outdoor-temperature.label = Température minimale
|
||||
channel-type.openweathermap.forecasted-min-outdoor-temperature.description = La température extérieure minimale prévue.
|
||||
|
||||
channel-type.openweathermap.forecasted-max-outdoor-temperature.label = Température maximale
|
||||
channel-type.openweathermap.forecasted-max-outdoor-temperature.description = La température extérieure maximale prévue.
|
||||
|
||||
channel-type.openweathermap.forecasted-barometric-pressure.label = Pression barométrique prévue
|
||||
channel-type.openweathermap.forecasted-barometric-pressure.description = La pression barométrique prévue.
|
||||
|
||||
channel-type.openweathermap.forecasted-atmospheric-humidity.label = Humidité atmosphérique prévue
|
||||
channel-type.openweathermap.forecasted-atmospheric-humidity.description = L'humidité relative atmosphérique prévue.
|
||||
|
||||
channel-type.openweathermap.forecasted-wind-speed.label = Vitesse prévue du vent
|
||||
channel-type.openweathermap.forecasted-wind-speed.description = La vitesse prévue du vent.
|
||||
|
||||
channel-type.openweathermap.forecasted-wind-direction.label = Direction prévue du vent
|
||||
channel-type.openweathermap.forecasted-wind-direction.description = La direction prévue du vent exprimée sous forme d'angle.
|
||||
|
||||
channel-type.openweathermap.gust-speed.label = Vitesse des rafales de vent
|
||||
channel-type.openweathermap.gust-speed.description = La vitesse actuelle des rafales de vent.
|
||||
|
||||
channel-type.openweathermap.forecasted-gust-speed.label = Vitesse prévue des rafales de vent
|
||||
channel-type.openweathermap.forecasted-gust-speed.description = La vitesse prévue des rafales de vent.
|
||||
|
||||
channel-type.openweathermap.cloudiness.label = Nébulosité
|
||||
channel-type.openweathermap.cloudiness.description = La nébulosité actuelle.
|
||||
|
||||
channel-type.openweathermap.forecasted-cloudiness.label = Nébulosité prévue
|
||||
channel-type.openweathermap.forecasted-cloudiness.description = La nébulosité prévue.
|
||||
|
||||
channel-type.openweathermap.visibility.label = Distance de visibilité
|
||||
channel-type.openweathermap.visibility.description = La distance de visibilité.
|
||||
|
||||
channel-type.openweathermap.rain.label = Pluie
|
||||
channel-type.openweathermap.rain.description = La quantité de pluie dans la dernière heure.
|
||||
|
||||
channel-type.openweathermap.forecasted-rain.label = Pluie prévue
|
||||
channel-type.openweathermap.forecasted-rain.description = La quantité prévue de pluie.
|
||||
|
||||
channel-type.openweathermap.snow.label = Neige
|
||||
channel-type.openweathermap.snow.description = La quantité de neige dans la dernière heure.
|
||||
|
||||
channel-type.openweathermap.forecasted-snow.label = Neige prévue
|
||||
channel-type.openweathermap.forecasted-snow.description = La quantité prévue de neige.
|
||||
|
||||
channel-type.openweathermap.uvindex.label = Indice UV
|
||||
channel-type.openweathermap.uvindex.description = L'indice UV actuel.
|
||||
|
||||
channel-type.openweathermap.forecasted-uvindex.label = Indice UV prévu
|
||||
channel-type.openweathermap.forecasted-uvindex.description = L'indice UV prévu.
|
||||
|
||||
# thing status
|
||||
offline.conf-error-missing-apikey = Le paramètre 'apikey' doit être configuré.
|
||||
offline.conf-error-invalid-apikey = Clé API invalide. Veuillez consulter https://openweathermap.org/faq#error401 pour plus d''informations.
|
||||
offline.conf-error-not-supported-refreshInterval = Le paramètre 'refreshInterval' doit être au moins de 10 minutes.
|
||||
offline.conf-error-not-supported-language = Le paramètre 'language' choisi n''est pas supporté.
|
||||
|
||||
offline.conf-error-missing-location = Le paramètre 'location' doit être configuré.
|
||||
offline.conf-error-parsing-location = Le paramètre 'location' n''a pas pu être séparé en latitude et en longitude.
|
||||
offline.conf-error-not-supported-number-of-hours = Le paramètre 'forecastHours' doit être compris entre 0 et 120 - par incrément de 3.
|
||||
offline.conf-error-not-supported-number-of-days = Le paramètre 'forecastDays' doit être compris entre 0 et 16.
|
||||
offline.conf-error-not-supported-uvindex-number-of-days = Le paramètre 'forecastDays' doit être compris entre 1 et 8.
|
||||
|
||||
# discovery result
|
||||
discovery.openweathermap.weather-and-forecast.api.local.label = Météo locale et prévisions
|
||||
discovery.openweathermap.uvindex.api.local.label = Indice UV local
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="openweathermap"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<!-- OpenWeatherMap Binding -->
|
||||
<bridge-type id="weather-api">
|
||||
<label>OpenWeatherMap Account</label>
|
||||
<description>Provides access to the OpenWeatherMap API.</description>
|
||||
|
||||
<representation-property>apikey</representation-property>
|
||||
|
||||
<config-description-ref uri="bridge-type:openweathermap:weather-api"/>
|
||||
</bridge-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,341 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="openweathermap"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<!-- Channel groups for OpenWeatherMap Binding -->
|
||||
<channel-group-type id="station">
|
||||
<label>Weather Station</label>
|
||||
<description>This is a weather station.</description>
|
||||
<channels>
|
||||
<channel id="id" typeId="station-id"/>
|
||||
<channel id="name" typeId="station-name"/>
|
||||
<channel id="location" typeId="system.location">
|
||||
<description>Location of the weather station or the city.</description>
|
||||
</channel>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="weather">
|
||||
<label>Current Weather</label>
|
||||
<description>This is the current weather.</description>
|
||||
<channels>
|
||||
<channel id="time-stamp" typeId="time-stamp"/>
|
||||
<channel id="condition" typeId="condition"/>
|
||||
<channel id="condition-id" typeId="condition-id"/>
|
||||
<channel id="icon" typeId="condition-icon"/>
|
||||
<channel id="icon-id" typeId="condition-icon-id"/>
|
||||
<channel id="temperature" typeId="system.outdoor-temperature"/>
|
||||
<channel id="apparent-temperature" typeId="apparent-temperature"/>
|
||||
<channel id="pressure" typeId="system.barometric-pressure"/>
|
||||
<channel id="humidity" typeId="system.atmospheric-humidity"/>
|
||||
<channel id="wind-speed" typeId="system.wind-speed"/>
|
||||
<channel id="wind-direction" typeId="system.wind-direction"/>
|
||||
<channel id="gust-speed" typeId="gust-speed"/>
|
||||
<channel id="cloudiness" typeId="cloudiness"/>
|
||||
<channel id="rain" typeId="rain"/>
|
||||
<channel id="snow" typeId="snow"/>
|
||||
<channel id="visibility" typeId="visibility"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="hourlyForecast">
|
||||
<label>3 Hour Forecast</label>
|
||||
<description>This is the 5 day / 3 hour weather forecast.</description>
|
||||
<channels>
|
||||
<channel id="time-stamp" typeId="hourly-forecast-time-stamp"/>
|
||||
<channel id="condition" typeId="forecasted-condition"/>
|
||||
<channel id="condition-id" typeId="condition-id"/>
|
||||
<channel id="icon" typeId="condition-icon"/>
|
||||
<channel id="icon-id" typeId="condition-icon-id"/>
|
||||
<channel id="temperature" typeId="forecasted-outdoor-temperature"/>
|
||||
<channel id="min-temperature" typeId="forecasted-min-outdoor-temperature"/>
|
||||
<channel id="max-temperature" typeId="forecasted-max-outdoor-temperature"/>
|
||||
<channel id="apparent-temperature" typeId="forecasted-apparent-temperature"/>
|
||||
<channel id="pressure" typeId="forecasted-barometric-pressure"/>
|
||||
<channel id="humidity" typeId="forecasted-atmospheric-humidity"/>
|
||||
<channel id="wind-speed" typeId="forecasted-wind-speed"/>
|
||||
<channel id="wind-direction" typeId="forecasted-wind-direction"/>
|
||||
<channel id="gust-speed" typeId="forecasted-gust-speed"/>
|
||||
<channel id="cloudiness" typeId="forecasted-cloudiness"/>
|
||||
<channel id="rain" typeId="forecasted-rain"/>
|
||||
<channel id="snow" typeId="forecasted-snow"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="dailyForecast">
|
||||
<label>Daily Forecast</label>
|
||||
<description>This is the 16 day / daily weather forecast.</description>
|
||||
<channels>
|
||||
<channel id="time-stamp" typeId="daily-forecast-time-stamp"/>
|
||||
<channel id="condition" typeId="forecasted-condition"/>
|
||||
<channel id="condition-id" typeId="condition-id"/>
|
||||
<channel id="icon" typeId="condition-icon"/>
|
||||
<channel id="icon-id" typeId="condition-icon-id"/>
|
||||
<channel id="min-temperature" typeId="forecasted-min-outdoor-temperature"/>
|
||||
<channel id="max-temperature" typeId="forecasted-max-outdoor-temperature"/>
|
||||
<channel id="apparent-temperature" typeId="forecasted-apparent-temperature"/>
|
||||
<channel id="pressure" typeId="forecasted-barometric-pressure"/>
|
||||
<channel id="humidity" typeId="forecasted-atmospheric-humidity"/>
|
||||
<channel id="wind-speed" typeId="forecasted-wind-speed"/>
|
||||
<channel id="wind-direction" typeId="forecasted-wind-direction"/>
|
||||
<channel id="gust-speed" typeId="forecasted-gust-speed"/>
|
||||
<channel id="cloudiness" typeId="forecasted-cloudiness"/>
|
||||
<channel id="rain" typeId="forecasted-rain"/>
|
||||
<channel id="snow" typeId="forecasted-snow"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="uvindex">
|
||||
<label>Current UV Index</label>
|
||||
<description>This is the current UV Index.</description>
|
||||
<channels>
|
||||
<channel id="time-stamp" typeId="daily-forecast-time-stamp"/>
|
||||
<channel id="uvindex" typeId="uvindex"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="uvindexForecast">
|
||||
<label>Forecasted UV Index</label>
|
||||
<description>This is the forecasted UV Index.</description>
|
||||
<channels>
|
||||
<channel id="time-stamp" typeId="daily-forecast-time-stamp"/>
|
||||
<channel id="uvindex" typeId="forecasted-uvindex"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<!-- Channels for OpenWeatherMap Binding -->
|
||||
<channel-type id="station-id">
|
||||
<item-type>String</item-type>
|
||||
<label>Station Id</label>
|
||||
<description>Id of the weather station or the city.</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="station-name">
|
||||
<item-type>String</item-type>
|
||||
<label>Station Name</label>
|
||||
<description>Name of the weather station or the city.</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="time-stamp">
|
||||
<item-type>DateTime</item-type>
|
||||
<label>Observation Time</label>
|
||||
<description>Time of data observation.</description>
|
||||
<category>Time</category>
|
||||
<state readOnly="true" pattern="%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="hourly-forecast-time-stamp">
|
||||
<item-type>DateTime</item-type>
|
||||
<label>Forecast Time</label>
|
||||
<description>Time of data forecasted.</description>
|
||||
<category>Time</category>
|
||||
<state readOnly="true" pattern="%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="daily-forecast-time-stamp">
|
||||
<item-type>DateTime</item-type>
|
||||
<label>Forecast Date</label>
|
||||
<description>Date of data forecasted.</description>
|
||||
<category>Time</category>
|
||||
<state readOnly="true" pattern="%1$tY-%1$tm-%1$td"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="condition">
|
||||
<item-type>String</item-type>
|
||||
<label>Weather Condition</label>
|
||||
<description>Current weather condition.</description>
|
||||
<category>Sun_Clouds</category>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="forecasted-condition">
|
||||
<item-type>String</item-type>
|
||||
<label>Forecasted Weather Condition</label>
|
||||
<description>Forecasted weather condition.</description>
|
||||
<category>Sun_Clouds</category>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="condition-id" advanced="true">
|
||||
<item-type>String</item-type>
|
||||
<label>Weather Condition Id</label>
|
||||
<description>Id of the weather condition.</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="condition-icon">
|
||||
<item-type>Image</item-type>
|
||||
<label>Icon</label>
|
||||
<description>Icon representing the weather condition.</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="condition-icon-id" advanced="true">
|
||||
<item-type>String</item-type>
|
||||
<label>Icon Id</label>
|
||||
<description>Id of the icon to create the URL.</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="forecasted-outdoor-temperature">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Forecasted Temperature</label>
|
||||
<description>Forecasted outdoor temperature.</description>
|
||||
<category>Temperature</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="forecasted-min-outdoor-temperature">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Minimum Temperature</label>
|
||||
<description>Minimum forecasted outdoor temperature.</description>
|
||||
<category>Temperature</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="forecasted-max-outdoor-temperature">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Maximum Temperature</label>
|
||||
<description>Maximum forecasted outdoor temperature.</description>
|
||||
<category>Temperature</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="apparent-temperature">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Apparent Temperature</label>
|
||||
<description>Current apparent temperature.</description>
|
||||
<category>Temperature</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="forecasted-apparent-temperature">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Forecasted Apparent Temperature</label>
|
||||
<description>Forecasted apparent temperature.</description>
|
||||
<category>Temperature</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="forecasted-barometric-pressure">
|
||||
<item-type>Number:Pressure</item-type>
|
||||
<label>Forecasted Pressure</label>
|
||||
<description>Forecasted barometric pressure.</description>
|
||||
<category>Pressure</category>
|
||||
<state readOnly="true" pattern="%.3f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="forecasted-atmospheric-humidity">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Forecasted Humidity</label>
|
||||
<description>Forecasted atmospheric relative humidity.</description>
|
||||
<category>Humidity</category>
|
||||
<state readOnly="true" pattern="%.0f %%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="forecasted-wind-speed">
|
||||
<item-type>Number:Speed</item-type>
|
||||
<label>Forecasted Wind Speed</label>
|
||||
<description>Forecasted wind speed.</description>
|
||||
<category>Wind</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="forecasted-wind-direction">
|
||||
<item-type>Number:Angle</item-type>
|
||||
<label>Forecasted Wind Direction</label>
|
||||
<description>Forecasted wind direction expressed as an angle.</description>
|
||||
<category>Wind</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="gust-speed" advanced="true">
|
||||
<item-type>Number:Speed</item-type>
|
||||
<label>Gust Speed</label>
|
||||
<description>Current gust speed.</description>
|
||||
<category>Wind</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="forecasted-gust-speed" advanced="true">
|
||||
<item-type>Number:Speed</item-type>
|
||||
<label>Forecasted Gust Speed</label>
|
||||
<description>Forecasted gust speed.</description>
|
||||
<category>Wind</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="cloudiness">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Cloudiness</label>
|
||||
<description>Current cloudiness.</description>
|
||||
<category>Clouds</category>
|
||||
<state readOnly="true" min="0" max="100" pattern="%d %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="forecasted-cloudiness">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Forecasted Cloudiness</label>
|
||||
<description>Forecasted cloudiness.</description>
|
||||
<category>Clouds</category>
|
||||
<state readOnly="true" min="0" max="100" pattern="%d %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="rain">
|
||||
<item-type>Number:Length</item-type>
|
||||
<label>Rain</label>
|
||||
<description>Rain volume of the last hour.</description>
|
||||
<category>Rain</category>
|
||||
<state readOnly="true" pattern="%.2f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="forecasted-rain">
|
||||
<item-type>Number:Length</item-type>
|
||||
<label>Forecasted Rain</label>
|
||||
<description>Forecasted rain volume.</description>
|
||||
<category>Rain</category>
|
||||
<state readOnly="true" pattern="%.2f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="snow">
|
||||
<item-type>Number:Length</item-type>
|
||||
<label>Snow</label>
|
||||
<description>Snow volume of the last hour.</description>
|
||||
<category>Snow</category>
|
||||
<state readOnly="true" pattern="%.2f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="forecasted-snow">
|
||||
<item-type>Number:Length</item-type>
|
||||
<label>Forecasted Snow</label>
|
||||
<description>Forecasted snow volume.</description>
|
||||
<category>Snow</category>
|
||||
<state readOnly="true" pattern="%.2f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="uvindex">
|
||||
<item-type>Number</item-type>
|
||||
<label>UV Index</label>
|
||||
<description>Current UV Index.</description>
|
||||
<state readOnly="true" pattern="%.1f"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="forecasted-uvindex">
|
||||
<item-type>Number</item-type>
|
||||
<label>Forecasted UV Index</label>
|
||||
<description>Forecasted UV Index.</description>
|
||||
<state readOnly="true" pattern="%.1f"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="visibility">
|
||||
<item-type>Number:Length</item-type>
|
||||
<label>Visibility</label>
|
||||
<description>Current visibility.</description>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,119 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="openweathermap"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<!-- OpenWeatherMap Binding -->
|
||||
<thing-type id="weather-and-forecast">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="weather-api"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>Weather and Forecast</label>
|
||||
<description>Provides current weather and forecast data from the OpenWeatherMap API.</description>
|
||||
|
||||
<channel-groups>
|
||||
<channel-group id="station" typeId="station"/>
|
||||
<channel-group id="current" typeId="weather"/>
|
||||
<channel-group id="forecastHours03" typeId="hourlyForecast">
|
||||
<label>3 Hours Forecast</label>
|
||||
<description>This is the weather forecast for the next 3 hours.</description>
|
||||
</channel-group>
|
||||
<channel-group id="forecastHours06" typeId="hourlyForecast">
|
||||
<label>6 Hours Forecast</label>
|
||||
<description>This is the weather forecast in 6 hours.</description>
|
||||
</channel-group>
|
||||
<channel-group id="forecastHours09" typeId="hourlyForecast">
|
||||
<label>9 Hours Forecast</label>
|
||||
<description>This is the weather forecast in 9 hours.</description>
|
||||
</channel-group>
|
||||
<channel-group id="forecastHours12" typeId="hourlyForecast">
|
||||
<label>12 Hours Forecast</label>
|
||||
<description>This is the weather forecast in 12 hours.</description>
|
||||
</channel-group>
|
||||
<channel-group id="forecastHours15" typeId="hourlyForecast">
|
||||
<label>15 Hours Forecast</label>
|
||||
<description>This is the weather forecast in 15 hours.</description>
|
||||
</channel-group>
|
||||
<channel-group id="forecastHours18" typeId="hourlyForecast">
|
||||
<label>18 Hours Forecast</label>
|
||||
<description>This is the weather forecast in 18 hours.</description>
|
||||
</channel-group>
|
||||
<channel-group id="forecastHours21" typeId="hourlyForecast">
|
||||
<label>21 Hours Forecast</label>
|
||||
<description>This is the weather forecast in 21 hours.</description>
|
||||
</channel-group>
|
||||
<channel-group id="forecastHours24" typeId="hourlyForecast">
|
||||
<label>24 Hours Forecast</label>
|
||||
<description>This is the weather forecast in 24 hours.</description>
|
||||
</channel-group>
|
||||
<channel-group id="forecastToday" typeId="dailyForecast">
|
||||
<label>Todays Forecast</label>
|
||||
<description>This is the weather forecast for today.</description>
|
||||
</channel-group>
|
||||
<channel-group id="forecastTomorrow" typeId="dailyForecast">
|
||||
<label>Tomorrows Forecast</label>
|
||||
<description>This is the weather forecast for tomorrow.</description>
|
||||
</channel-group>
|
||||
<channel-group id="forecastDay2" typeId="dailyForecast">
|
||||
<label>2 Day Forecast</label>
|
||||
<description>This is the weather forecast in two days.</description>
|
||||
</channel-group>
|
||||
<channel-group id="forecastDay3" typeId="dailyForecast">
|
||||
<label>3 Day Forecast</label>
|
||||
<description>This is the weather forecast in three days.</description>
|
||||
</channel-group>
|
||||
<channel-group id="forecastDay4" typeId="dailyForecast">
|
||||
<label>4 Day Forecast</label>
|
||||
<description>This is the weather forecast in four days.</description>
|
||||
</channel-group>
|
||||
<channel-group id="forecastDay5" typeId="dailyForecast">
|
||||
<label>5 Day Forecast</label>
|
||||
<description>This is the weather forecast in five days.</description>
|
||||
</channel-group>
|
||||
</channel-groups>
|
||||
|
||||
<representation-property>location</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:openweathermap:weather-and-forecast"/>
|
||||
</thing-type>
|
||||
|
||||
<thing-type id="uvindex">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="weather-api"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>UV Index</label>
|
||||
<description>Provides UV Index data from the OpenWeatherMap API.</description>
|
||||
|
||||
<channel-groups>
|
||||
<channel-group id="current" typeId="uvindex"/>
|
||||
<channel-group id="forecastTomorrow" typeId="uvindexForecast">
|
||||
<label>Tomorrows Forecast</label>
|
||||
<description>This is the UV Index forecast for tomorrow.</description>
|
||||
</channel-group>
|
||||
<channel-group id="forecastDay2" typeId="uvindexForecast">
|
||||
<label>2 Day Forecast</label>
|
||||
<description>This is the UV Index forecast in two days.</description>
|
||||
</channel-group>
|
||||
<channel-group id="forecastDay3" typeId="uvindexForecast">
|
||||
<label>3 Day Forecast</label>
|
||||
<description>This is the UV Index forecast in three days.</description>
|
||||
</channel-group>
|
||||
<channel-group id="forecastDay4" typeId="uvindexForecast">
|
||||
<label>4 Day Forecast</label>
|
||||
<description>This is the UV Index forecast in four days.</description>
|
||||
</channel-group>
|
||||
<channel-group id="forecastDay5" typeId="uvindexForecast">
|
||||
<label>5 Day Forecast</label>
|
||||
<description>This is the UV Index forecast in five days.</description>
|
||||
</channel-group>
|
||||
</channel-groups>
|
||||
|
||||
<representation-property>location</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:openweathermap:uvindex"/>
|
||||
</thing-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
Reference in New Issue
Block a user