[openweathermap] Add support for One Call API #7308 (#9062)

* OH 3.0 version of the Openweathermap Onecall API Binding extension

Signed-off-by: wolfii <wolfgang.klimt@consol.de>
This commit is contained in:
Wolfgang Klimt
2020-11-30 21:09:20 +01:00
committed by GitHub
parent 7fe7b60f83
commit 6afbe23ea6
32 changed files with 3831 additions and 17 deletions

View File

@@ -36,6 +36,10 @@ public class OpenWeatherMapBindingConstants {
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");
// One Call API forecast
public static final ThingTypeUID THING_TYPE_ONECALL_WEATHER_AND_FORECAST = new ThingTypeUID(BINDING_ID, "onecall");
// One Call API historical data
public static final ThingTypeUID THING_TYPE_ONECALL_HISTORY = new ThingTypeUID(BINDING_ID, "onecall-history");
// List of all properties
public static final String CONFIG_API_KEY = "apikey";
@@ -49,6 +53,14 @@ public class OpenWeatherMapBindingConstants {
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");
public static final ChannelGroupTypeUID CHANNEL_GROUP_TYPE_ONECALL_MINUTELY_FORECAST = new ChannelGroupTypeUID(
BINDING_ID, "oneCallMinutely");
public static final ChannelGroupTypeUID CHANNEL_GROUP_TYPE_ONECALL_HOURLY_FORECAST = new ChannelGroupTypeUID(
BINDING_ID, "oneCallHourly");
public static final ChannelGroupTypeUID CHANNEL_GROUP_TYPE_ONECALL_DAILY_FORECAST = new ChannelGroupTypeUID(
BINDING_ID, "oneCallDaily");
public static final ChannelGroupTypeUID CHANNEL_GROUP_TYPE_ONECALL_CURRENT = new ChannelGroupTypeUID(BINDING_ID,
"oneCallCurrent");
// List of all channel groups
public static final String CHANNEL_GROUP_STATION = "station";
@@ -56,30 +68,47 @@ public class OpenWeatherMapBindingConstants {
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";
public static final String CHANNEL_GROUP_ONECALL_CURRENT = "current";
public static final String CHANNEL_GROUP_ONECALL_HISTORY = "history";
public static final String CHANNEL_GROUP_ONECALL_TODAY = "forecastToday";
public static final String CHANNEL_GROUP_ONECALL_TOMORROW = "forecastTomorrow";
// 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_SUNRISE = "sunrise";
public static final String CHANNEL_SUNSET = "sunset";
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_APPARENT_MORNING = "apparent-morning";
public static final String CHANNEL_APPARENT_DAY = "apparent-day";
public static final String CHANNEL_APPARENT_EVENING = "apparent-evening";
public static final String CHANNEL_APPARENT_NIGHT = "apparent-night";
public static final String CHANNEL_MIN_TEMPERATURE = "min-temperature";
public static final String CHANNEL_MAX_TEMPERATURE = "max-temperature";
public static final String CHANNEL_MORNING_TEMPERATURE = "morning-temperature";
public static final String CHANNEL_DAY_TEMPERATURE = "day-temperature";
public static final String CHANNEL_EVENING_TEMPERATURE = "evening-temperature";
public static final String CHANNEL_NIGHT_TEMPERATURE = "night-temperature";
public static final String CHANNEL_DEW_POINT = "dew-point";
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_PRECIP_PROBABILITY = "precip-probability";
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";
public static final String CHANNEL_PRECIPITATION = "precipitation";
// List of all configuration
public static final String CONFIG_FORECAST_DAYS = "forecastDays";

View File

@@ -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;
/**
* The {@link OpenWeatherMapOneCallConfiguration} is the class used to match the
* {@link org.openhab.binding.openweathermap.internal.handler.OpenWeatherMapOneCallHandler}s configuration.
*
* @author Wolfgang Klimt - Initial contribution
*/
@NonNullByDefault
public class OpenWeatherMapOneCallConfiguration extends OpenWeatherMapLocationConfiguration {
public int forecastMinutes;
public int forecastHours;
public int forecastDays;
}

View File

@@ -0,0 +1,26 @@
/**
* 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;
/**
* The {@link OpenWeatherMapOneCallHistoryConfiguration} is the class used to match the
* {@link org.openhab.binding.openweathermap.internal.handler.OpenWeatherMapOneCallHistoryHandler}s configuration.
*
* @author Wolfgang Klimt - Initial contribution
*/
@NonNullByDefault
public class OpenWeatherMapOneCallHistoryConfiguration extends OpenWeatherMapLocationConfiguration {
public int historyDay;
}

View File

@@ -16,10 +16,11 @@ 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.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
@@ -38,6 +39,8 @@ import org.openhab.binding.openweathermap.internal.dto.OpenWeatherMapJsonDailyFo
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.dto.onecall.OpenWeatherMapOneCallAPIData;
import org.openhab.binding.openweathermap.internal.dto.onecallhist.OpenWeatherMapOneCallHistAPIData;
import org.openhab.binding.openweathermap.internal.handler.OpenWeatherMapAPIHandler;
import org.openhab.core.cache.ByteArrayFileCache;
import org.openhab.core.cache.ExpiringCacheMap;
@@ -73,6 +76,8 @@ public class OpenWeatherMapConnection {
private static final String PARAM_LON = "lon";
private static final String PARAM_LANG = "lang";
private static final String PARAM_FORECAST_CNT = "cnt";
private static final String PARAM_HISTORY_DATE = "dt";
private static final String PARAM_EXCLUDE = "exclude";
// Current weather data (see https://openweathermap.org/current)
private static final String WEATHER_URL = "https://api.openweathermap.org/data/2.5/weather";
@@ -85,6 +90,9 @@ public class OpenWeatherMapConnection {
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";
// One Call API (see https://openweathermap.org/api/one-call-api )
private static final String ONECALL_URL = "https://api.openweathermap.org/data/2.5/onecall";
private static final String ONECALL_HISTORY_URL = "https://api.openweathermap.org/data/2.5/onecall/timemachine";
private final OpenWeatherMapAPIHandler handler;
private final HttpClient httpClient;
@@ -227,7 +235,7 @@ public class OpenWeatherMapConnection {
if (IMAGE_CACHE.containsKey(url)) {
try {
return new RawType(IMAGE_CACHE.get(url), PNG_CONTENT_TYPE);
} catch (IOException e) {
} catch (Exception e) {
LoggerFactory.getLogger(OpenWeatherMapConnection.class)
.trace("Failed to download the content of URL '{}'", url, e);
}
@@ -245,6 +253,65 @@ public class OpenWeatherMapConnection {
return HttpUtil.downloadImage(url);
}
/**
* Get Weather data from the OneCall API for the given location. See https://openweathermap.org/api/one-call-api for
* details
*
* @param location location represented as {@link PointType}
* @param excludeMinutely if true, will not fetch minutely forecast data from the server
* @param excludeHourly if true, will not fethh hourly forecast data from the server
* @param excludeDaily if true, will not fetch hourly forecast data from the server
* @return
* @throws JsonSyntaxException
* @throws OpenWeatherMapCommunicationException
* @throws OpenWeatherMapConfigurationException
*/
public synchronized @Nullable OpenWeatherMapOneCallAPIData getOneCallAPIData(@Nullable PointType location,
boolean excludeMinutely, boolean excludeHourly, boolean excludeDaily)
throws JsonSyntaxException, OpenWeatherMapCommunicationException, OpenWeatherMapConfigurationException {
Map<String, String> params = getRequestParams(handler.getOpenWeatherMapAPIConfig(), location);
StringBuilder exclude = new StringBuilder("");
if (excludeMinutely) {
exclude.append("minutely");
}
if (excludeHourly) {
exclude.append(exclude.length() > 0 ? "," : "").append("hourly");
}
if (excludeDaily) {
exclude.append(exclude.length() > 0 ? "," : "").append("daily");
}
logger.debug("Exclude: '{}'", exclude);
if (exclude.length() > 0) {
params.put(PARAM_EXCLUDE, exclude.toString());
}
return gson.fromJson(getResponseFromCache(buildURL(ONECALL_URL, params)), OpenWeatherMapOneCallAPIData.class);
}
/**
* Get the historical weather data from the OneCall API for the given location and the given number of days in the
* past.
* As of now, OpenWeatherMap supports this function for up to 5 days in the past. However, this may change in the
* future,
* so we don't enforce this limit here. See https://openweathermap.org/api/one-call-api for details
*
* @param location location represented as {@link PointType}
* @param days number of days in the past, relative to the current time.
* @return
* @throws JsonSyntaxException
* @throws OpenWeatherMapCommunicationException
* @throws OpenWeatherMapConfigurationException
*/
public synchronized @Nullable OpenWeatherMapOneCallHistAPIData getOneCallHistAPIData(@Nullable PointType location,
int days)
throws JsonSyntaxException, OpenWeatherMapCommunicationException, OpenWeatherMapConfigurationException {
Map<String, String> params = getRequestParams(handler.getOpenWeatherMapAPIConfig(), location);
// the API requests the history as timestamp in Unix time format.
params.put(PARAM_HISTORY_DATE,
Long.toString(ZonedDateTime.now(ZoneId.of("UTC")).minusDays(days).toEpochSecond()));
return gson.fromJson(getResponseFromCache(buildURL(ONECALL_HISTORY_URL, params)),
OpenWeatherMapOneCallHistAPIData.class);
}
private Map<String, String> getRequestParams(OpenWeatherMapAPIConfiguration config, @Nullable PointType location) {
if (location == null) {
throw new OpenWeatherMapConfigurationException("@text/offline.conf-error-missing-location");

View File

@@ -128,6 +128,8 @@ public class OpenWeatherMapDiscoveryService extends AbstractDiscoveryService {
ThingUID bridgeUID = bridgeHandler.getThing().getUID();
createWeatherAndForecastResult(locationString, bridgeUID);
createUVIndexResult(locationString, bridgeUID);
createOneCallResult(locationString, bridgeUID);
createOneCallHistoryResult(locationString, bridgeUID);
}
private void createWeatherAndForecastResult(String location, ThingUID bridgeUID) {
@@ -141,4 +143,17 @@ public class OpenWeatherMapDiscoveryService extends AbstractDiscoveryService {
.withLabel("Local UV Index").withProperty(CONFIG_LOCATION, location)
.withRepresentationProperty(CONFIG_LOCATION).withBridge(bridgeUID).build());
}
private void createOneCallResult(String location, ThingUID bridgeUID) {
thingDiscovered(
DiscoveryResultBuilder.create(new ThingUID(THING_TYPE_ONECALL_WEATHER_AND_FORECAST, bridgeUID, LOCAL))
.withLabel("One Call API weather and forecast").withProperty(CONFIG_LOCATION, location)
.withRepresentationProperty(CONFIG_LOCATION).withBridge(bridgeUID).build());
}
private void createOneCallHistoryResult(String location, ThingUID bridgeUID) {
thingDiscovered(DiscoveryResultBuilder.create(new ThingUID(THING_TYPE_ONECALL_HISTORY, bridgeUID, LOCAL))
.withLabel("One Call API history data").withProperty(CONFIG_LOCATION, location)
.withRepresentationProperty(CONFIG_LOCATION).withBridge(bridgeUID).build());
}
}

View File

@@ -0,0 +1,219 @@
/**
* 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.onecall;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* Holds the data from the deserialised JSON response. Created using http://www.jsonschema2pojo.org/.
* Settings:
* Annotation Style: GSON
* Use primitive types
* Use double numbers
* allow additional properties
*
* @author Wolfgang Klimt - Initial contribution
*/
public class Current {
@SerializedName("dt")
@Expose
private int dt;
@SerializedName("sunrise")
@Expose
private int sunrise;
@SerializedName("sunset")
@Expose
private int sunset;
@SerializedName("temp")
@Expose
private double temp;
@SerializedName("feels_like")
@Expose
private double feelsLike;
@SerializedName("pressure")
@Expose
private int pressure;
@SerializedName("humidity")
@Expose
private int humidity;
@SerializedName("dew_point")
@Expose
private double dewPoint;
@SerializedName("uvi")
@Expose
private double uvi;
@SerializedName("clouds")
@Expose
private int clouds;
@SerializedName("visibility")
@Expose
private int visibility;
@SerializedName("wind_speed")
@Expose
private double windSpeed;
@SerializedName("wind_deg")
@Expose
private int windDeg;
@SerializedName("wind_gust")
@Expose
private double windGust;
@SerializedName("weather")
@Expose
private List<Weather> weather = null;
@SerializedName("rain")
@Expose
private Rain rain;
@SerializedName("snow")
@Expose
private Snow snow;
public int getDt() {
return dt;
}
public void setDt(int dt) {
this.dt = dt;
}
public int getSunrise() {
return sunrise;
}
public void setSunrise(int sunrise) {
this.sunrise = sunrise;
}
public int getSunset() {
return sunset;
}
public void setSunset(int sunset) {
this.sunset = sunset;
}
public double getTemp() {
return temp;
}
public void setTemp(double temp) {
this.temp = temp;
}
public double getFeelsLike() {
return feelsLike;
}
public void setFeelsLike(double feelsLike) {
this.feelsLike = feelsLike;
}
public int getPressure() {
return pressure;
}
public void setPressure(int pressure) {
this.pressure = pressure;
}
public int getHumidity() {
return humidity;
}
public void setHumidity(int humidity) {
this.humidity = humidity;
}
public double getDewPoint() {
return dewPoint;
}
public void setDewPoint(double dewPoint) {
this.dewPoint = dewPoint;
}
public double getUvi() {
return uvi;
}
public void setUvi(double uvi) {
this.uvi = uvi;
}
public int getClouds() {
return clouds;
}
public void setClouds(int clouds) {
this.clouds = clouds;
}
public int getVisibility() {
return visibility;
}
public void setVisibility(int visibility) {
this.visibility = visibility;
}
public double getWindSpeed() {
return windSpeed;
}
public void setWindSpeed(double windSpeed) {
this.windSpeed = windSpeed;
}
public int getWindDeg() {
return windDeg;
}
public void setWindDeg(int windDeg) {
this.windDeg = windDeg;
}
public double getWindGust() {
return windGust;
}
public void setWindGust(double windGust) {
this.windGust = windGust;
}
public List<Weather> getWeather() {
return weather;
}
public void setWeather(List<Weather> weather) {
this.weather = weather;
}
public Rain getRain() {
return rain;
}
public void setRain(Rain rain) {
this.rain = rain;
}
public Snow getSnow() {
return snow;
}
public void setSnow(Snow snow) {
this.snow = snow;
}
}

View File

@@ -0,0 +1,230 @@
/**
* 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.onecall;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* Holds the data from the deserialised JSON response. Created using http://www.jsonschema2pojo.org/.
* Settings:
* Annotation Style: GSON
* Use primitive types
* Use double numbers
* allow additional properties
*
* @author Wolfgang Klimt - Initial contribution
*/
public class Daily {
@SerializedName("dt")
@Expose
private int dt;
@SerializedName("sunrise")
@Expose
private int sunrise;
@SerializedName("sunset")
@Expose
private int sunset;
@SerializedName("temp")
@Expose
private Temp temp;
@SerializedName("feels_like")
@Expose
private FeelsLike feelsLike;
@SerializedName("pressure")
@Expose
private int pressure;
@SerializedName("humidity")
@Expose
private int humidity;
@SerializedName("dew_point")
@Expose
private double dewPoint;
@SerializedName("wind_speed")
@Expose
private double windSpeed;
@SerializedName("wind_deg")
@Expose
private int windDeg;
@SerializedName("wind_gust")
@Expose
private double windGust;
@SerializedName("weather")
@Expose
private List<Weather> weather = null;
@SerializedName("clouds")
@Expose
private int clouds;
@SerializedName("pop")
@Expose
private double pop;
@SerializedName("visibility")
@Expose
private int visibility;
@SerializedName("rain")
@Expose
private double rain;
@SerializedName("snow")
@Expose
private double snow;
@SerializedName("uvi")
@Expose
private double uvi;
public int getDt() {
return dt;
}
public void setDt(int dt) {
this.dt = dt;
}
public int getSunrise() {
return sunrise;
}
public void setSunrise(int sunrise) {
this.sunrise = sunrise;
}
public int getSunset() {
return sunset;
}
public void setSunset(int sunset) {
this.sunset = sunset;
}
public Temp getTemp() {
return temp;
}
public void setTemp(Temp temp) {
this.temp = temp;
}
public FeelsLike getFeelsLike() {
return feelsLike;
}
public void setFeelsLike(FeelsLike feelsLike) {
this.feelsLike = feelsLike;
}
public int getPressure() {
return pressure;
}
public void setPressure(int pressure) {
this.pressure = pressure;
}
public int getHumidity() {
return humidity;
}
public void setHumidity(int humidity) {
this.humidity = humidity;
}
public double getDewPoint() {
return dewPoint;
}
public void setDewPoint(double dewPoint) {
this.dewPoint = dewPoint;
}
public double getWindSpeed() {
return windSpeed;
}
public void setWindSpeed(double windSpeed) {
this.windSpeed = windSpeed;
}
public int getWindDeg() {
return windDeg;
}
public void setWindDeg(int windDeg) {
this.windDeg = windDeg;
}
public double getWindGust() {
return windGust;
}
public void setWindGust(double windGust) {
this.windGust = windGust;
}
public List<Weather> getWeather() {
return weather;
}
public void setWeather(List<Weather> weather) {
this.weather = weather;
}
public int getClouds() {
return clouds;
}
public void setClouds(int clouds) {
this.clouds = clouds;
}
public double getPop() {
return pop;
}
public void setPop(double pop) {
this.pop = pop;
}
public double getRain() {
return rain;
}
public void setRain(double rain) {
this.rain = rain;
}
public double getUvi() {
return uvi;
}
public void setUvi(double uvi) {
this.uvi = uvi;
}
public int getVisibility() {
return visibility;
}
public void setVisibility(int visibility) {
this.visibility = visibility;
}
public double getSnow() {
return snow;
}
public void setSnow(double snow) {
this.snow = snow;
}
}

View File

@@ -0,0 +1,74 @@
/**
* 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.onecall;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* Holds the data from the deserialised JSON response. Created using http://www.jsonschema2pojo.org/.
* Settings:
* Annotation Style: GSON
* Use primitive types
* Use double numbers
* allow additional properties
*
* @author Wolfgang Klimt - Initial contribution
*/
public class FeelsLike {
@SerializedName("day")
@Expose
private double day;
@SerializedName("night")
@Expose
private double night;
@SerializedName("eve")
@Expose
private double eve;
@SerializedName("morn")
@Expose
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;
}
}

View File

@@ -0,0 +1,197 @@
/**
* 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.onecall;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* Holds the data from the deserialised JSON response. Created using http://www.jsonschema2pojo.org/.
* Settings:
* Annotation Style: GSON
* Use primitive types
* Use double numbers
* allow additional properties
*
* @author Wolfgang Klimt - Initial contribution
*/
public class Hourly {
@SerializedName("dt")
@Expose
private int dt;
@SerializedName("temp")
@Expose
private double temp;
@SerializedName("feels_like")
@Expose
private double feelsLike;
@SerializedName("pressure")
@Expose
private int pressure;
@SerializedName("humidity")
@Expose
private int humidity;
@SerializedName("dew_point")
@Expose
private double dewPoint;
@SerializedName("clouds")
@Expose
private int clouds;
@SerializedName("visibility")
@Expose
private int visibility;
@SerializedName("wind_speed")
@Expose
private double windSpeed;
@SerializedName("wind_deg")
@Expose
private int windDeg;
@SerializedName("wind_gust")
@Expose
private double windGust;
@SerializedName("weather")
@Expose
private List<Weather> weather = null;
@SerializedName("pop")
@Expose
private double pop;
@SerializedName("rain")
@Expose
private Rain rain;
@SerializedName("snow")
@Expose
private Snow snow;
public int getDt() {
return dt;
}
public void setDt(int dt) {
this.dt = dt;
}
public double getTemp() {
return temp;
}
public void setTemp(double temp) {
this.temp = temp;
}
public double getFeelsLike() {
return feelsLike;
}
public void setFeelsLike(double feelsLike) {
this.feelsLike = feelsLike;
}
public int getPressure() {
return pressure;
}
public void setPressure(int pressure) {
this.pressure = pressure;
}
public int getHumidity() {
return humidity;
}
public void setHumidity(int humidity) {
this.humidity = humidity;
}
public double getDewPoint() {
return dewPoint;
}
public void setDewPoint(double dewPoint) {
this.dewPoint = dewPoint;
}
public int getClouds() {
return clouds;
}
public void setClouds(int clouds) {
this.clouds = clouds;
}
public int getVisibility() {
return visibility;
}
public void setVisibility(int visibility) {
this.visibility = visibility;
}
public double getWindSpeed() {
return windSpeed;
}
public void setWindSpeed(double windSpeed) {
this.windSpeed = windSpeed;
}
public int getWindDeg() {
return windDeg;
}
public void setWindDeg(int windDeg) {
this.windDeg = windDeg;
}
public double getWindGust() {
return windGust;
}
public void setWindGust(double windGust) {
this.windGust = windGust;
}
public List<Weather> getWeather() {
return weather;
}
public void setWeather(List<Weather> weather) {
this.weather = weather;
}
public double getPop() {
return pop;
}
public void setPop(double pop) {
this.pop = pop;
}
public Rain getRain() {
return rain;
}
public void setRain(Rain rain) {
this.rain = rain;
}
public Snow getSnow() {
return snow;
}
public void setSnow(Snow snow) {
this.snow = snow;
}
}

View File

@@ -0,0 +1,52 @@
/**
* 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.onecall;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* Holds the data from the deserialised JSON response. Created using http://www.jsonschema2pojo.org/.
* Settings:
* Annotation Style: GSON
* Use primitive types
* Use double numbers
* allow additional properties
*
* @author Wolfgang Klimt - Initial contribution
*/
public class Minutely {
@SerializedName("dt")
@Expose
private int dt;
@SerializedName("precipitation")
@Expose
private double precipitation;
public int getDt() {
return dt;
}
public void setDt(int dt) {
this.dt = dt;
}
public double getPrecipitation() {
return precipitation;
}
public void setPrecipitation(double precipitation) {
this.precipitation = precipitation;
}
}

View File

@@ -0,0 +1,120 @@
/**
* 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.onecall;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* Holds the data from the deserialised JSON response. Created using http://www.jsonschema2pojo.org/.
* Settings:
* Annotation Style: GSON
* Use primitive types
* Use double numbers
* allow additional properties
*
* @author Wolfgang Klimt - Initial contribution
*/
public class OpenWeatherMapOneCallAPIData {
@SerializedName("lat")
@Expose
private double lat;
@SerializedName("lon")
@Expose
private double lon;
@SerializedName("timezone")
@Expose
private String timezone;
@SerializedName("timezone_offset")
@Expose
private int timezoneOffset;
@SerializedName("current")
@Expose
private Current current;
@SerializedName("minutely")
@Expose
private List<Minutely> minutely = null;
@SerializedName("hourly")
@Expose
private List<Hourly> hourly = null;
@SerializedName("daily")
@Expose
private List<Daily> daily = null;
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 getTimezone() {
return timezone;
}
public void setTimezone(String timezone) {
this.timezone = timezone;
}
public int getTimezoneOffset() {
return timezoneOffset;
}
public void setTimezoneOffset(int timezoneOffset) {
this.timezoneOffset = timezoneOffset;
}
public Current getCurrent() {
return current;
}
public void setCurrent(Current current) {
this.current = current;
}
public List<Minutely> getMinutely() {
return minutely;
}
public void setMinutely(List<Minutely> minutely) {
this.minutely = minutely;
}
public List<Hourly> getHourly() {
return hourly;
}
public void setHourly(List<Hourly> hourly) {
this.hourly = hourly;
}
public List<Daily> getDaily() {
return daily;
}
public void setDaily(List<Daily> daily) {
this.daily = daily;
}
}

View File

@@ -0,0 +1,41 @@
/**
* 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.onecall;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* Holds the data from the deserialised JSON response. Created using http://www.jsonschema2pojo.org/.
* Settings:
* Annotation Style: GSON
* Use primitive types
* Use double numbers
* allow additional properties
*
* @author Wolfgang Klimt - Initial contribution
*/
public class Rain {
@SerializedName("1h")
@Expose
private double _1h;
public double get1h() {
return _1h;
}
public void set1h(double _1h) {
this._1h = _1h;
}
}

View File

@@ -0,0 +1,41 @@
/**
* 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.onecall;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* Holds the data from the deserialised JSON response. Created using http://www.jsonschema2pojo.org/.
* Settings:
* Annotation Style: GSON
* Use primitive types
* Use double numbers
* allow additional properties
*
* @author Wolfgang Klimt - Initial contribution
*/
public class Snow {
@SerializedName("1h")
@Expose
private double _1h;
public double get1h() {
return _1h;
}
public void set1h(double _1h) {
this._1h = _1h;
}
}

View File

@@ -0,0 +1,96 @@
/**
* 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.onecall;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* Holds the data from the deserialised JSON response. Created using http://www.jsonschema2pojo.org/.
* Settings:
* Annotation Style: GSON
* Use primitive types
* Use double numbers
* allow additional properties
*
* @author Wolfgang Klimt - Initial contribution
*/
public class Temp {
@SerializedName("day")
@Expose
private double day;
@SerializedName("min")
@Expose
private double min;
@SerializedName("max")
@Expose
private double max;
@SerializedName("night")
@Expose
private double night;
@SerializedName("eve")
@Expose
private double eve;
@SerializedName("morn")
@Expose
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;
}
}

View File

@@ -0,0 +1,74 @@
/**
* 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.onecall;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* Holds the data from the deserialised JSON response. Created using http://www.jsonschema2pojo.org/.
* Settings:
* Annotation Style: GSON
* Use primitive types
* Use double numbers
* allow additional properties
*
* @author Wolfgang Klimt - Initial contribution
*/
public class Weather {
@SerializedName("id")
@Expose
private int id;
@SerializedName("main")
@Expose
private String main;
@SerializedName("description")
@Expose
private String description;
@SerializedName("icon")
@Expose
private String icon;
public int getId() {
return id;
}
public void setId(int 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;
}
}

View File

@@ -0,0 +1,219 @@
/**
* 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.onecallhist;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* Holds the data from the deserialised JSON response. Created using http://www.jsonschema2pojo.org/.
* Settings:
* Annotation Style: GSON
* Use primitive types
* Use double numbers
* allow additional properties
*
* @author Wolfgang Klimt - Initial contribution
*/
public class Current {
@SerializedName("dt")
@Expose
private int dt;
@SerializedName("sunrise")
@Expose
private int sunrise;
@SerializedName("sunset")
@Expose
private int sunset;
@SerializedName("temp")
@Expose
private double temp;
@SerializedName("feels_like")
@Expose
private double feelsLike;
@SerializedName("pressure")
@Expose
private int pressure;
@SerializedName("humidity")
@Expose
private int humidity;
@SerializedName("dew_point")
@Expose
private double dewPoint;
@SerializedName("uvi")
@Expose
private double uvi;
@SerializedName("clouds")
@Expose
private int clouds;
@SerializedName("visibility")
@Expose
private int visibility;
@SerializedName("wind_speed")
@Expose
private double windSpeed;
@SerializedName("wind_deg")
@Expose
private int windDeg;
@SerializedName("wind_gust")
@Expose
private double windGust;
@SerializedName("weather")
@Expose
private List<Weather> weather = null;
@SerializedName("rain")
@Expose
private Rain rain;
@SerializedName("snow")
@Expose
private Snow snow;
public int getDt() {
return dt;
}
public void setDt(int dt) {
this.dt = dt;
}
public int getSunrise() {
return sunrise;
}
public void setSunrise(int sunrise) {
this.sunrise = sunrise;
}
public int getSunset() {
return sunset;
}
public void setSunset(int sunset) {
this.sunset = sunset;
}
public double getTemp() {
return temp;
}
public void setTemp(double temp) {
this.temp = temp;
}
public double getFeelsLike() {
return feelsLike;
}
public void setFeelsLike(double feelsLike) {
this.feelsLike = feelsLike;
}
public int getPressure() {
return pressure;
}
public void setPressure(int pressure) {
this.pressure = pressure;
}
public int getHumidity() {
return humidity;
}
public void setHumidity(int humidity) {
this.humidity = humidity;
}
public double getDewPoint() {
return dewPoint;
}
public void setDewPoint(double dewPoint) {
this.dewPoint = dewPoint;
}
public double getUvi() {
return uvi;
}
public void setUvi(double uvi) {
this.uvi = uvi;
}
public int getClouds() {
return clouds;
}
public void setClouds(int clouds) {
this.clouds = clouds;
}
public int getVisibility() {
return visibility;
}
public void setVisibility(int visibility) {
this.visibility = visibility;
}
public double getWindSpeed() {
return windSpeed;
}
public void setWindSpeed(double windSpeed) {
this.windSpeed = windSpeed;
}
public int getWindDeg() {
return windDeg;
}
public void setWindDeg(int windDeg) {
this.windDeg = windDeg;
}
public double getWindGust() {
return windGust;
}
public void setWindGust(double windGust) {
this.windGust = windGust;
}
public List<Weather> getWeather() {
return weather;
}
public void setWeather(List<Weather> weather) {
this.weather = weather;
}
public Rain getRain() {
return rain;
}
public void setRain(Rain rain) {
this.rain = rain;
}
public Snow getSnow() {
return snow;
}
public void setSnow(Snow snow) {
this.snow = snow;
}
}

View File

@@ -0,0 +1,186 @@
/**
* 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.onecallhist;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* Holds the data from the deserialised JSON response. Created using http://www.jsonschema2pojo.org/.
* Settings:
* Annotation Style: GSON
* Use primitive types
* Use double numbers
* allow additional properties
*
* @author Wolfgang Klimt - Initial contribution
*/
public class Hourly {
@SerializedName("dt")
@Expose
private int dt;
@SerializedName("temp")
@Expose
private double temp;
@SerializedName("feels_like")
@Expose
private double feelsLike;
@SerializedName("pressure")
@Expose
private int pressure;
@SerializedName("humidity")
@Expose
private int humidity;
@SerializedName("dew_point")
@Expose
private double dewPoint;
@SerializedName("clouds")
@Expose
private int clouds;
@SerializedName("visibility")
@Expose
private int visibility;
@SerializedName("wind_speed")
@Expose
private double windSpeed;
@SerializedName("wind_deg")
@Expose
private int windDeg;
@SerializedName("wind_gust")
@Expose
private double windGust;
@SerializedName("weather")
@Expose
private List<Weather> weather = null;
@SerializedName("rain")
@Expose
private Rain rain;
@SerializedName("snow")
@Expose
private Snow snow;
public int getDt() {
return dt;
}
public void setDt(int dt) {
this.dt = dt;
}
public double getTemp() {
return temp;
}
public void setTemp(double temp) {
this.temp = temp;
}
public double getFeelsLike() {
return feelsLike;
}
public void setFeelsLike(double feelsLike) {
this.feelsLike = feelsLike;
}
public int getPressure() {
return pressure;
}
public void setPressure(int pressure) {
this.pressure = pressure;
}
public int getHumidity() {
return humidity;
}
public void setHumidity(int humidity) {
this.humidity = humidity;
}
public double getDewPoint() {
return dewPoint;
}
public void setDewPoint(double dewPoint) {
this.dewPoint = dewPoint;
}
public int getClouds() {
return clouds;
}
public void setClouds(int clouds) {
this.clouds = clouds;
}
public int getVisibility() {
return visibility;
}
public void setVisibility(int visibility) {
this.visibility = visibility;
}
public double getWindSpeed() {
return windSpeed;
}
public void setWindSpeed(double windSpeed) {
this.windSpeed = windSpeed;
}
public int getWindDeg() {
return windDeg;
}
public void setWindDeg(int windDeg) {
this.windDeg = windDeg;
}
public double getWindGust() {
return windGust;
}
public void setWindGust(double windGust) {
this.windGust = windGust;
}
public List<Weather> getWeather() {
return weather;
}
public void setWeather(List<Weather> weather) {
this.weather = weather;
}
public Rain getRain() {
return rain;
}
public void setRain(Rain rain) {
this.rain = rain;
}
public Snow getSnow() {
return snow;
}
public void setSnow(Snow snow) {
this.snow = snow;
}
}

View File

@@ -0,0 +1,98 @@
/**
* 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.onecallhist;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* Holds the data from the deserialised JSON response. Created using http://www.jsonschema2pojo.org/.
* Settings:
* Annotation Style: GSON
* Use primitive types
* Use double numbers
* allow additional properties
*
* @author Wolfgang Klimt - Initial contribution
*/
public class OpenWeatherMapOneCallHistAPIData {
@SerializedName("lat")
@Expose
private double lat;
@SerializedName("lon")
@Expose
private double lon;
@SerializedName("timezone")
@Expose
private String timezone;
@SerializedName("timezone_offset")
@Expose
private int timezoneOffset;
@SerializedName("current")
@Expose
private Current current;
@SerializedName("hourly")
@Expose
private List<Hourly> hourly = null;
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 getTimezone() {
return timezone;
}
public void setTimezone(String timezone) {
this.timezone = timezone;
}
public int getTimezoneOffset() {
return timezoneOffset;
}
public void setTimezoneOffset(int timezoneOffset) {
this.timezoneOffset = timezoneOffset;
}
public Current getCurrent() {
return current;
}
public void setCurrent(Current current) {
this.current = current;
}
public List<Hourly> getHourly() {
return hourly;
}
public void setHourly(List<Hourly> hourly) {
this.hourly = hourly;
}
}

View File

@@ -0,0 +1,41 @@
/**
* 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.onecallhist;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* Holds the data from the deserialised JSON response. Created using http://www.jsonschema2pojo.org/.
* Settings:
* Annotation Style: GSON
* Use primitive types
* Use double numbers
* allow additional properties
*
* @author Wolfgang Klimt - Initial contribution
*/
public class Rain {
@SerializedName("1h")
@Expose
private double _1h;
public double get1h() {
return _1h;
}
public void set1h(double _1h) {
this._1h = _1h;
}
}

View File

@@ -0,0 +1,41 @@
/**
* 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.onecallhist;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* Holds the data from the deserialised JSON response. Created using http://www.jsonschema2pojo.org/.
* Settings:
* Annotation Style: GSON
* Use primitive types
* Use double numbers
* allow additional properties
*
* @author Wolfgang Klimt - Initial contribution
*/
public class Snow {
@SerializedName("1h")
@Expose
private double _1h;
public double get1h() {
return _1h;
}
public void set1h(double _1h) {
this._1h = _1h;
}
}

View File

@@ -0,0 +1,74 @@
/**
* 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.onecallhist;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
/**
* Holds the data from the deserialised JSON response. Created using http://www.jsonschema2pojo.org/.
* Settings:
* Annotation Style: GSON
* Use primitive types
* Use double numbers
* allow additional properties
*
* @author Wolfgang Klimt - Initial contribution
*/
public class Weather {
@SerializedName("id")
@Expose
private int id;
@SerializedName("main")
@Expose
private String main;
@SerializedName("description")
@Expose
private String description;
@SerializedName("icon")
@Expose
private String icon;
public int getId() {
return id;
}
public void setId(int 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;
}
}

View File

@@ -26,10 +26,7 @@ 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.binding.openweathermap.internal.handler.*;
import org.openhab.core.config.discovery.DiscoveryService;
import org.openhab.core.i18n.LocaleProvider;
import org.openhab.core.i18n.LocationProvider;
@@ -100,6 +97,10 @@ public class OpenWeatherMapHandlerFactory extends BaseThingHandlerFactory {
return new OpenWeatherMapWeatherAndForecastHandler(thing, timeZoneProvider);
} else if (THING_TYPE_UVINDEX.equals(thingTypeUID)) {
return new OpenWeatherMapUVIndexHandler(thing, timeZoneProvider);
} else if (THING_TYPE_ONECALL_WEATHER_AND_FORECAST.equals(thingTypeUID)) {
return new OpenWeatherMapOneCallHandler(thing, timeZoneProvider);
} else if (THING_TYPE_ONECALL_HISTORY.equals(thingTypeUID)) {
return new OpenWeatherMapOneCallHistoryHandler(thing, timeZoneProvider);
}
return null;

View File

@@ -69,8 +69,9 @@ 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()));
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections
.unmodifiableSet(Stream.of(THING_TYPE_WEATHER_AND_FORECAST, THING_TYPE_UVINDEX,
THING_TYPE_ONECALL_WEATHER_AND_FORECAST, THING_TYPE_ONECALL_HISTORY).collect(Collectors.toSet()));
private final TimeZoneProvider timeZoneProvider;
@@ -151,8 +152,8 @@ public abstract class AbstractOpenWeatherMapHandler extends BaseThingHandler {
*
* @param connection {@link OpenWeatherMapConnection} instance
* @return true, if the request for the OpenWeatherMap data was successful
* @throws OpenWeatherMapCommunicationException
* @throws OpenWeatherMapConfigurationException
* @throws OpenWeatherMapCommunicationException if there is a problem retrieving the data
* @throws OpenWeatherMapConfigurationException if there is a configuration error
*/
protected abstract boolean requestData(OpenWeatherMapConnection connection)
throws OpenWeatherMapCommunicationException, OpenWeatherMapConfigurationException;
@@ -205,7 +206,8 @@ public abstract class AbstractOpenWeatherMapHandler extends BaseThingHandler {
}
protected List<Channel> createChannelsForGroup(String channelGroupId, ChannelGroupTypeUID channelGroupTypeUID) {
logger.debug("Building channel group '{}' for thing '{}'.", channelGroupId, getThing().getUID());
logger.debug("Building channel group '{}' for thing '{}' and GroupType '{}'.", channelGroupId,
getThing().getUID(), channelGroupTypeUID);
List<Channel> channels = new ArrayList<>();
ThingHandlerCallback callback = getCallback();
if (callback != null) {
@@ -221,6 +223,7 @@ public abstract class AbstractOpenWeatherMapHandler extends BaseThingHandler {
channels.add(newChannel);
}
}
logger.debug("Built channels: {}", channels);
return channels;
}

View File

@@ -0,0 +1,636 @@
/**
* 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 org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.openweathermap.internal.config.OpenWeatherMapOneCallConfiguration;
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.onecall.*;
import org.openhab.core.i18n.TimeZoneProvider;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.thing.*;
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 OpenWeatherMapOneCallHandler} is responsible for handling commands, which are sent to one of
* the channels.
*
* @author Wolfgang Klimt - Initial contribution
*/
@NonNullByDefault
public class OpenWeatherMapOneCallHandler extends AbstractOpenWeatherMapHandler {
private final Logger logger = LoggerFactory.getLogger(OpenWeatherMapOneCallHandler.class);
private static final String CHANNEL_GROUP_MINUTELY_FORECAST_PREFIX = "forecastMinutes";
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]*)");
private static final Pattern CHANNEL_GROUP_MINUTELY_FORECAST_PREFIX_PATTERN = Pattern
.compile(CHANNEL_GROUP_MINUTELY_FORECAST_PREFIX + "([0-9]*)");
private @Nullable OpenWeatherMapOneCallAPIData weatherData;
private int forecastMinutes = 60;
private int forecastHours = 24;
private int forecastDays = 8;
public OpenWeatherMapOneCallHandler(Thing thing, final TimeZoneProvider timeZoneProvider) {
super(thing, timeZoneProvider);
}
@Override
public void initialize() {
super.initialize();
logger.debug("Initialize OpenWeatherMapOneCallHandler handler '{}'.", getThing().getUID());
OpenWeatherMapOneCallConfiguration config = getConfigAs(OpenWeatherMapOneCallConfiguration.class);
boolean configValid = true;
int newForecastMinutes = config.forecastMinutes;
if (newForecastMinutes < 0 || newForecastMinutes > 60) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"@text/offline.conf-error-not-supported-onecall-number-of-minutes");
configValid = false;
}
int newForecastHours = config.forecastHours;
if (newForecastHours < 0 || newForecastHours > 48) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"@text/offline.conf-error-not-supported-onecall-number-of-hours");
configValid = false;
}
int newForecastDays = config.forecastDays;
if (newForecastDays < 0 || newForecastDays > 8) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"@text/offline.conf-error-not-supported-onecall-number-of-days");
configValid = false;
}
if (configValid) {
logger.debug("Rebuilding thing '{}'.", getThing().getUID());
List<Channel> toBeAddedChannels = new ArrayList<>();
List<Channel> toBeRemovedChannels = new ArrayList<>();
toBeAddedChannels
.addAll(createChannelsForGroup(CHANNEL_GROUP_ONECALL_CURRENT, CHANNEL_GROUP_TYPE_ONECALL_CURRENT));
if (forecastMinutes != newForecastMinutes) {
logger.debug("forecastMinutes changed from {} to {}. Rebuilding minutely forecast channel groups.",
forecastMinutes, newForecastMinutes);
if (forecastMinutes > newForecastMinutes) {
for (int i = newForecastMinutes + 1; i <= forecastMinutes; i++) {
toBeRemovedChannels.addAll(removeChannelsOfGroup(
CHANNEL_GROUP_MINUTELY_FORECAST_PREFIX + ((i < 10) ? "0" : "") + Integer.toString(i)));
}
} else {
for (int i = forecastMinutes + 1; i <= newForecastMinutes; i++) {
toBeAddedChannels.addAll(createChannelsForGroup(
CHANNEL_GROUP_MINUTELY_FORECAST_PREFIX + ((i < 10) ? "0" : "") + Integer.toString(i),
CHANNEL_GROUP_TYPE_ONECALL_MINUTELY_FORECAST));
}
}
forecastMinutes = newForecastMinutes;
}
if (forecastHours != newForecastHours) {
logger.debug("ForecastHours changed from {} to {}. Rebuilding hourly forecast channel groups.",
forecastHours, newForecastHours);
if (forecastHours > newForecastHours) {
for (int i = newForecastHours + 1; i <= forecastHours; i++) {
toBeRemovedChannels.addAll(removeChannelsOfGroup(
CHANNEL_GROUP_HOURLY_FORECAST_PREFIX + ((i < 10) ? "0" : "") + Integer.toString(i)));
}
} else {
for (int i = forecastHours + 1; i <= newForecastHours; i++) {
toBeAddedChannels.addAll(createChannelsForGroup(
CHANNEL_GROUP_HOURLY_FORECAST_PREFIX + ((i < 10) ? "0" : "") + Integer.toString(i),
CHANNEL_GROUP_TYPE_ONECALL_HOURLY_FORECAST));
}
}
forecastHours = newForecastHours;
}
if (forecastDays != newForecastDays) {
logger.debug("ForecastDays changed from {} to {}. Rebuilding daily forecast channel groups.",
forecastDays, newForecastDays);
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_ONECALL_DAILY_FORECAST));
}
if (forecastDays <= 1 && newForecastDays > 1) {
toBeAddedChannels.addAll(createChannelsForGroup(CHANNEL_GROUP_FORECAST_TOMORROW,
CHANNEL_GROUP_TYPE_ONECALL_DAILY_FORECAST));
}
for (int i = Math.max(forecastDays, 2); i < newForecastDays; i++) {
toBeAddedChannels.addAll(
createChannelsForGroup(CHANNEL_GROUP_DAILY_FORECAST_PREFIX + Integer.toString(i),
CHANNEL_GROUP_TYPE_ONECALL_DAILY_FORECAST));
}
}
forecastDays = newForecastDays;
}
logger.debug("toBeRemovedChannels: {}. toBeAddedChannels: {}", toBeRemovedChannels, toBeAddedChannels);
ThingBuilder builder = editThing().withoutChannels(toBeRemovedChannels);
for (Channel channel : toBeAddedChannels) {
builder.withChannel(channel);
}
updateThing(builder.build());
updateStatus(ThingStatus.ONLINE);
}
}
@Override
protected boolean requestData(OpenWeatherMapConnection connection)
throws OpenWeatherMapCommunicationException, OpenWeatherMapConfigurationException {
logger.debug("Update weather and forecast data of thing '{}'.", getThing().getUID());
try {
weatherData = connection.getOneCallAPIData(location, forecastMinutes == 0, forecastHours == 0,
forecastDays == 0);
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();
logger.debug("OneCallHandler: updateChannel {}, groupID {}", channelUID, channelGroupId);
switch (channelGroupId) {
case CHANNEL_GROUP_ONECALL_CURRENT:
updateCurrentChannel(channelUID);
break;
case CHANNEL_GROUP_ONECALL_TODAY:
updateDailyForecastChannel(channelUID, 0);
break;
case CHANNEL_GROUP_ONECALL_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))) >= 1
&& i <= 48) {
updateHourlyForecastChannel(channelUID, (i - 1));
break;
}
Matcher dailyForecastMatcher = CHANNEL_GROUP_DAILY_FORECAST_PREFIX_PATTERN.matcher(channelGroupId);
if (dailyForecastMatcher.find() && (i = Integer.parseInt(dailyForecastMatcher.group(1))) >= 1
&& i <= 7) {
updateDailyForecastChannel(channelUID, i);
break;
}
Matcher minutelyForecastMatcher = CHANNEL_GROUP_MINUTELY_FORECAST_PREFIX_PATTERN
.matcher(channelGroupId);
if (minutelyForecastMatcher.find() && (i = Integer.parseInt(minutelyForecastMatcher.group(1))) >= 1
&& i <= 60) {
updateMinutelyForecastChannel(channelUID, i - 1);
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();
OpenWeatherMapOneCallAPIData localWeatherData = weatherData;
if (localWeatherData != null) {
State state = UnDefType.UNDEF;
switch (channelId) {
case CHANNEL_STATION_LOCATION:
state = getPointTypeState(localWeatherData.getLat(), localWeatherData.getLon());
break;
case CHANNEL_TIME_STAMP:
state = getDateTimeTypeState(localWeatherData.getCurrent().getDt());
break;
case CHANNEL_SUNRISE:
state = getDateTimeTypeState(localWeatherData.getCurrent().getSunrise());
break;
case CHANNEL_SUNSET:
state = getDateTimeTypeState(localWeatherData.getCurrent().getSunset());
break;
case CHANNEL_CONDITION:
if (!localWeatherData.getCurrent().getWeather().isEmpty()) {
state = getStringTypeState(localWeatherData.getCurrent().getWeather().get(0).getDescription());
}
break;
case CHANNEL_CONDITION_ID:
if (!localWeatherData.getCurrent().getWeather().isEmpty()) {
state = getStringTypeState(
Integer.toString(localWeatherData.getCurrent().getWeather().get(0).getId()));
}
break;
case CHANNEL_CONDITION_ICON:
if (!localWeatherData.getCurrent().getWeather().isEmpty()) {
state = getRawTypeState(OpenWeatherMapConnection
.getWeatherIcon(localWeatherData.getCurrent().getWeather().get(0).getIcon()));
}
break;
case CHANNEL_CONDITION_ICON_ID:
if (!localWeatherData.getCurrent().getWeather().isEmpty()) {
state = getStringTypeState(localWeatherData.getCurrent().getWeather().get(0).getIcon());
}
break;
case CHANNEL_TEMPERATURE:
state = getQuantityTypeState(localWeatherData.getCurrent().getTemp(), CELSIUS);
break;
case CHANNEL_APPARENT_TEMPERATURE:
state = getQuantityTypeState(localWeatherData.getCurrent().getFeelsLike(), CELSIUS);
break;
case CHANNEL_PRESSURE:
state = getQuantityTypeState(localWeatherData.getCurrent().getPressure(), HECTO(PASCAL));
break;
case CHANNEL_HUMIDITY:
state = getQuantityTypeState(localWeatherData.getCurrent().getHumidity(), PERCENT);
break;
case CHANNEL_DEW_POINT:
state = getQuantityTypeState(localWeatherData.getCurrent().getDewPoint(), CELSIUS);
break;
case CHANNEL_WIND_SPEED:
state = getQuantityTypeState(localWeatherData.getCurrent().getWindSpeed(), METRE_PER_SECOND);
break;
case CHANNEL_WIND_DIRECTION:
state = getQuantityTypeState(localWeatherData.getCurrent().getWindDeg(), DEGREE_ANGLE);
break;
case CHANNEL_GUST_SPEED:
state = getQuantityTypeState(localWeatherData.getCurrent().getWindGust(), METRE_PER_SECOND);
break;
case CHANNEL_CLOUDINESS:
state = getQuantityTypeState(localWeatherData.getCurrent().getClouds(), PERCENT);
break;
case CHANNEL_UVINDEX:
state = getDecimalTypeState(localWeatherData.getCurrent().getUvi());
break;
case CHANNEL_RAIN:
Rain rain = localWeatherData.getCurrent().getRain();
state = getQuantityTypeState(rain == null ? 0 : rain.get1h(), MILLI(METRE));
break;
case CHANNEL_SNOW:
Snow snow = localWeatherData.getCurrent().getSnow();
state = getQuantityTypeState(snow == null ? 0 : snow.get1h(), MILLI(METRE));
break;
case CHANNEL_VISIBILITY:
@Nullable
State tempstate = new QuantityType<>(localWeatherData.getCurrent().getVisibility(), METRE)
.toUnit(KILO(METRE));
state = (tempstate == null ? state : tempstate);
break;
default:
// This should not happen
logger.warn("Unknown channel id {} in onecall current weather data", channelId);
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);
}
}
private void updateMinutelyForecastChannel(ChannelUID channelUID, int count) {
String channelId = channelUID.getIdWithoutGroup();
String channelGroupId = channelUID.getGroupId();
OpenWeatherMapOneCallAPIData localWeatherData = weatherData;
if (forecastMinutes == 0) {
logger.warn(
"Can't update channel group {} because forecastMinutes is set to '0'. Please adjust config accordingly",
channelGroupId);
return;
}
if (localWeatherData != null && localWeatherData.getMinutely().size() > count) {
org.openhab.binding.openweathermap.internal.dto.onecall.Minutely forecastData = localWeatherData
.getMinutely().get(count);
State state = UnDefType.UNDEF;
switch (channelId) {
case CHANNEL_TIME_STAMP:
state = getDateTimeTypeState(forecastData.getDt());
break;
case CHANNEL_PRECIPITATION:
double precipitation = forecastData.getPrecipitation();
state = getQuantityTypeState(precipitation, MILLI(METRE));
break;
default:
// This should not happen
logger.warn("Unknown channel id {} in onecall minutely weather data", channelId);
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 the number of the hour referenced by the channel
*/
private void updateHourlyForecastChannel(ChannelUID channelUID, int count) {
String channelId = channelUID.getIdWithoutGroup();
String channelGroupId = channelUID.getGroupId();
if (forecastHours == 0) {
logger.warn(
"Can't update channel group {} because forecastHours is set to '0'. Please adjust config accordingly",
channelGroupId);
return;
}
OpenWeatherMapOneCallAPIData localWeatherData = weatherData;
if (localWeatherData != null && localWeatherData.getHourly().size() > count) {
org.openhab.binding.openweathermap.internal.dto.onecall.Hourly forecastData = localWeatherData.getHourly()
.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(Integer.toString(forecastData.getWeather().get(0).getId()));
}
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.getTemp(), CELSIUS);
break;
case CHANNEL_APPARENT_TEMPERATURE:
state = getQuantityTypeState(forecastData.getFeelsLike(), CELSIUS);
break;
case CHANNEL_PRESSURE:
state = getQuantityTypeState(forecastData.getPressure(), HECTO(PASCAL));
break;
case CHANNEL_HUMIDITY:
state = getQuantityTypeState(forecastData.getHumidity(), PERCENT);
break;
case CHANNEL_DEW_POINT:
state = getQuantityTypeState(forecastData.getDewPoint(), CELSIUS);
break;
case CHANNEL_WIND_SPEED:
state = getQuantityTypeState(forecastData.getWindSpeed(), METRE_PER_SECOND);
break;
case CHANNEL_WIND_DIRECTION:
state = getQuantityTypeState(forecastData.getWindDeg(), DEGREE_ANGLE);
break;
case CHANNEL_GUST_SPEED:
state = getQuantityTypeState(forecastData.getWindGust(), METRE_PER_SECOND);
break;
case CHANNEL_CLOUDINESS:
state = getQuantityTypeState(forecastData.getClouds(), PERCENT);
break;
case CHANNEL_VISIBILITY:
@Nullable
State tempstate = new QuantityType<>(localWeatherData.getCurrent().getVisibility(), METRE)
.toUnit(KILO(METRE));
state = (tempstate == null ? state : tempstate);
case CHANNEL_PRECIP_PROBABILITY:
state = getQuantityTypeState(forecastData.getPop() * 100.0, PERCENT);
break;
case CHANNEL_RAIN:
Rain rain = forecastData.getRain();
state = getQuantityTypeState(rain == null ? 0 : rain.get1h(), MILLI(METRE));
break;
case CHANNEL_SNOW:
Snow snow = forecastData.getSnow();
state = getQuantityTypeState(snow == null ? 0 : snow.get1h(), MILLI(METRE));
break;
default:
// This should not happen
logger.warn("Unknown channel id {} in onecall hourly weather data", channelId);
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();
if (forecastDays == 0) {
logger.warn(
"Can't update channel group {} because forecastDays is set to '0'. Please adjust config accordingly",
channelGroupId);
return;
}
@Nullable
OpenWeatherMapOneCallAPIData localWeatherData = weatherData;
if (localWeatherData != null && localWeatherData.getDaily().size() > count) {
org.openhab.binding.openweathermap.internal.dto.onecall.Daily forecastData = localWeatherData.getDaily()
.get(count);
State state = UnDefType.UNDEF;
Temp temp;
FeelsLike feelsLike;
switch (channelId) {
case CHANNEL_TIME_STAMP:
state = getDateTimeTypeState(forecastData.getDt());
break;
case CHANNEL_SUNRISE:
state = getDateTimeTypeState(forecastData.getSunrise());
break;
case CHANNEL_SUNSET:
state = getDateTimeTypeState(forecastData.getSunset());
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(Integer.toString(forecastData.getWeather().get(0).getId()));
}
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:
temp = forecastData.getTemp();
if (temp != null) {
state = getQuantityTypeState(temp.getMin(), CELSIUS);
}
break;
case CHANNEL_MAX_TEMPERATURE:
temp = forecastData.getTemp();
if (temp != null) {
state = getQuantityTypeState(temp.getMax(), CELSIUS);
}
break;
case CHANNEL_MORNING_TEMPERATURE:
temp = forecastData.getTemp();
if (temp != null) {
state = getQuantityTypeState(temp.getMorn(), CELSIUS);
}
break;
case CHANNEL_DAY_TEMPERATURE:
temp = forecastData.getTemp();
if (temp != null) {
state = getQuantityTypeState(temp.getDay(), CELSIUS);
}
break;
case CHANNEL_EVENING_TEMPERATURE:
temp = forecastData.getTemp();
if (temp != null) {
state = getQuantityTypeState(temp.getEve(), CELSIUS);
}
break;
case CHANNEL_NIGHT_TEMPERATURE:
temp = forecastData.getTemp();
if (temp != null) {
state = getQuantityTypeState(temp.getNight(), CELSIUS);
}
break;
case CHANNEL_APPARENT_DAY:
feelsLike = forecastData.getFeelsLike();
if (feelsLike != null) {
state = getQuantityTypeState(feelsLike.getDay(), CELSIUS);
}
break;
case CHANNEL_APPARENT_MORNING:
feelsLike = forecastData.getFeelsLike();
if (feelsLike != null) {
state = getQuantityTypeState(feelsLike.getMorn(), CELSIUS);
}
break;
case CHANNEL_APPARENT_EVENING:
feelsLike = forecastData.getFeelsLike();
if (feelsLike != null) {
state = getQuantityTypeState(feelsLike.getEve(), CELSIUS);
}
break;
case CHANNEL_APPARENT_NIGHT:
feelsLike = forecastData.getFeelsLike();
if (feelsLike != null) {
state = getQuantityTypeState(feelsLike.getNight(), 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.getWindSpeed(), METRE_PER_SECOND);
break;
case CHANNEL_WIND_DIRECTION:
state = getQuantityTypeState(forecastData.getWindDeg(), DEGREE_ANGLE);
break;
case CHANNEL_GUST_SPEED:
state = getQuantityTypeState(forecastData.getWindGust(), METRE_PER_SECOND);
break;
case CHANNEL_CLOUDINESS:
state = getQuantityTypeState(forecastData.getClouds(), PERCENT);
break;
case CHANNEL_DEW_POINT:
state = getQuantityTypeState(forecastData.getDewPoint(), CELSIUS);
break;
case CHANNEL_UVINDEX:
state = getDecimalTypeState(forecastData.getUvi());
break;
case CHANNEL_VISIBILITY:
@Nullable
State tempstate = new QuantityType<>(localWeatherData.getCurrent().getVisibility(), METRE)
.toUnit(KILO(METRE));
state = (tempstate == null ? state : tempstate);
case CHANNEL_PRECIP_PROBABILITY:
state = getQuantityTypeState(forecastData.getPop() * 100.0, PERCENT);
break;
case CHANNEL_RAIN:
state = getQuantityTypeState(forecastData.getRain(), MILLI(METRE));
break;
case CHANNEL_SNOW:
state = getQuantityTypeState(forecastData.getSnow(), MILLI(METRE));
break;
default:
// This should not happen
logger.warn("Unknown channel id {} in onecall daily weather data", channelId);
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);
}
}
}

View File

@@ -0,0 +1,317 @@
/**
* 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.HECTO;
import static org.openhab.core.library.unit.MetricPrefix.KILO;
import static org.openhab.core.library.unit.MetricPrefix.MILLI;
import static org.openhab.core.library.unit.SIUnits.*;
import static org.openhab.core.library.unit.SmartHomeUnits.*;
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.OpenWeatherMapOneCallHistoryConfiguration;
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.onecallhist.*;
import org.openhab.binding.openweathermap.internal.dto.onecallhist.OpenWeatherMapOneCallHistAPIData;
import org.openhab.core.i18n.TimeZoneProvider;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
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 OpenWeatherMapOneCallHistoryHandler} is responsible for handling commands, which are sent to one of
* the channels.
*
* @author Wolfgang Klimt - Initial contribution
*/
@NonNullByDefault
public class OpenWeatherMapOneCallHistoryHandler extends AbstractOpenWeatherMapHandler {
private final Logger logger = LoggerFactory.getLogger(OpenWeatherMapOneCallHistoryHandler.class);
private static final String CHANNEL_GROUP_HOURLY_FORECAST_PREFIX = "historyHours";
private static final Pattern CHANNEL_GROUP_HOURLY_FORECAST_PREFIX_PATTERN = Pattern
.compile(CHANNEL_GROUP_HOURLY_FORECAST_PREFIX + "([0-9]*)");
private @Nullable OpenWeatherMapOneCallHistAPIData weatherData;
// the relative day in history.
private int day = 0;
public OpenWeatherMapOneCallHistoryHandler(Thing thing, final TimeZoneProvider timeZoneProvider) {
super(thing, timeZoneProvider);
}
@Override
public void initialize() {
super.initialize();
OpenWeatherMapOneCallHistoryConfiguration config = getConfigAs(OpenWeatherMapOneCallHistoryConfiguration.class);
if (config.historyDay <= 0) {
logger.warn("historyDay value of {} is not supported", config.historyDay);
return;
}
/*
* As of now, only 5 days in history are supported by the one call API. As this may change in the future,
* we allow any value here and only log a warning if the value exceeds 5.
*/
if (config.historyDay > 5) {
logger.warn("History configuration of {} days may cause errors. You have been warned :-)",
config.historyDay);
}
day = config.historyDay;
logger.debug("Initialize OpenWeatherMapOneCallHistoryHandler handler '{}' with historyDay {}.",
getThing().getUID(), day);
updateStatus(ThingStatus.ONLINE);
}
@Override
protected boolean requestData(OpenWeatherMapConnection connection)
throws OpenWeatherMapCommunicationException, OpenWeatherMapConfigurationException {
logger.debug("Update weather and forecast data of thing '{}'.", getThing().getUID());
try {
weatherData = connection.getOneCallHistAPIData(location, day);
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_ONECALL_HISTORY:
updateHistoryCurrentChannel(channelUID);
break;
default:
int i;
Matcher hourlyForecastMatcher = CHANNEL_GROUP_HOURLY_FORECAST_PREFIX_PATTERN.matcher(channelGroupId);
if (hourlyForecastMatcher.find() && (i = Integer.parseInt(hourlyForecastMatcher.group(1))) >= 1
&& i <= 48) {
updateHourlyHistoryChannel(channelUID, i - 1);
break;
}
break;
}
}
/**
* Update the channel from the last OpenWeatherMap data retrieved.
*
* @param channelUID the id identifying the channel to be updated
*/
private void updateHistoryCurrentChannel(ChannelUID channelUID) {
String channelId = channelUID.getIdWithoutGroup();
String channelGroupId = channelUID.getGroupId();
OpenWeatherMapOneCallHistAPIData localWeatherData = weatherData;
if (localWeatherData != null) {
State state = UnDefType.UNDEF;
switch (channelId) {
case CHANNEL_STATION_LOCATION:
state = getPointTypeState(localWeatherData.getLat(), localWeatherData.getLon());
break;
case CHANNEL_TIME_STAMP:
state = getDateTimeTypeState(localWeatherData.getCurrent().getDt());
break;
case CHANNEL_SUNRISE:
state = getDateTimeTypeState(localWeatherData.getCurrent().getSunrise());
break;
case CHANNEL_SUNSET:
state = getDateTimeTypeState(localWeatherData.getCurrent().getSunset());
break;
case CHANNEL_CONDITION:
if (!localWeatherData.getCurrent().getWeather().isEmpty()) {
state = getStringTypeState(localWeatherData.getCurrent().getWeather().get(0).getDescription());
}
break;
case CHANNEL_CONDITION_ID:
if (!localWeatherData.getCurrent().getWeather().isEmpty()) {
state = getStringTypeState(
Integer.toString(localWeatherData.getCurrent().getWeather().get(0).getId()));
}
break;
case CHANNEL_CONDITION_ICON:
if (!localWeatherData.getCurrent().getWeather().isEmpty()) {
state = getRawTypeState(OpenWeatherMapConnection
.getWeatherIcon(localWeatherData.getCurrent().getWeather().get(0).getIcon()));
}
break;
case CHANNEL_CONDITION_ICON_ID:
if (!localWeatherData.getCurrent().getWeather().isEmpty()) {
state = getStringTypeState(localWeatherData.getCurrent().getWeather().get(0).getIcon());
}
break;
case CHANNEL_TEMPERATURE:
state = getQuantityTypeState(localWeatherData.getCurrent().getTemp(), CELSIUS);
break;
case CHANNEL_APPARENT_TEMPERATURE:
state = getQuantityTypeState(localWeatherData.getCurrent().getFeelsLike(), CELSIUS);
break;
case CHANNEL_PRESSURE:
state = getQuantityTypeState(localWeatherData.getCurrent().getPressure(), HECTO(PASCAL));
break;
case CHANNEL_HUMIDITY:
state = getQuantityTypeState(localWeatherData.getCurrent().getHumidity(), PERCENT);
break;
case CHANNEL_DEW_POINT:
state = getQuantityTypeState(localWeatherData.getCurrent().getDewPoint(), CELSIUS);
break;
case CHANNEL_WIND_SPEED:
state = getQuantityTypeState(localWeatherData.getCurrent().getWindSpeed(), METRE_PER_SECOND);
break;
case CHANNEL_WIND_DIRECTION:
state = getQuantityTypeState(localWeatherData.getCurrent().getWindDeg(), DEGREE_ANGLE);
break;
case CHANNEL_GUST_SPEED:
state = getQuantityTypeState(localWeatherData.getCurrent().getWindGust(), METRE_PER_SECOND);
break;
case CHANNEL_CLOUDINESS:
state = getQuantityTypeState(localWeatherData.getCurrent().getClouds(), PERCENT);
break;
case CHANNEL_UVINDEX:
state = getDecimalTypeState(localWeatherData.getCurrent().getUvi());
break;
case CHANNEL_RAIN:
Rain rain = localWeatherData.getCurrent().getRain();
state = getQuantityTypeState(rain == null ? 0 : rain.get1h(), MILLI(METRE));
break;
case CHANNEL_SNOW:
Snow snow = localWeatherData.getCurrent().getSnow();
state = getQuantityTypeState(snow == null ? 0 : snow.get1h(), MILLI(METRE));
break;
case CHANNEL_VISIBILITY:
@Nullable
State tempstate = new QuantityType<>(localWeatherData.getCurrent().getVisibility(), METRE)
.toUnit(KILO(METRE));
state = (tempstate == null ? state : tempstate);
break;
default:
// This should not happen
logger.warn("Unknown channel id {} in onecall current weather data", channelId);
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 the number of the hour referenced by the channel
*/
private void updateHourlyHistoryChannel(ChannelUID channelUID, int count) {
String channelId = channelUID.getIdWithoutGroup();
String channelGroupId = channelUID.getGroupId();
logger.debug("Updating hourly history data for channel {}, group {}, count {}", channelId, channelGroupId,
count);
OpenWeatherMapOneCallHistAPIData localWeatherData = weatherData;
if (localWeatherData != null && localWeatherData.getHourly().size() > count) {
Hourly historyData = localWeatherData.getHourly().get(count);
State state = UnDefType.UNDEF;
switch (channelId) {
case CHANNEL_TIME_STAMP:
state = getDateTimeTypeState(historyData.getDt());
break;
case CHANNEL_CONDITION:
if (!historyData.getWeather().isEmpty()) {
state = getStringTypeState(historyData.getWeather().get(0).getDescription());
}
break;
case CHANNEL_CONDITION_ID:
if (!historyData.getWeather().isEmpty()) {
state = getStringTypeState(Integer.toString(historyData.getWeather().get(0).getId()));
}
break;
case CHANNEL_CONDITION_ICON:
if (!historyData.getWeather().isEmpty()) {
state = getRawTypeState(
OpenWeatherMapConnection.getWeatherIcon(historyData.getWeather().get(0).getIcon()));
}
break;
case CHANNEL_CONDITION_ICON_ID:
if (!historyData.getWeather().isEmpty()) {
state = getStringTypeState(historyData.getWeather().get(0).getIcon());
}
break;
case CHANNEL_TEMPERATURE:
state = getQuantityTypeState(historyData.getTemp(), CELSIUS);
break;
case CHANNEL_APPARENT_TEMPERATURE:
state = getQuantityTypeState(historyData.getFeelsLike(), CELSIUS);
break;
case CHANNEL_PRESSURE:
state = getQuantityTypeState(historyData.getPressure(), HECTO(PASCAL));
break;
case CHANNEL_HUMIDITY:
state = getQuantityTypeState(historyData.getHumidity(), PERCENT);
break;
case CHANNEL_DEW_POINT:
state = getQuantityTypeState(historyData.getDewPoint(), CELSIUS);
break;
case CHANNEL_WIND_SPEED:
state = getQuantityTypeState(historyData.getWindSpeed(), METRE_PER_SECOND);
break;
case CHANNEL_WIND_DIRECTION:
state = getQuantityTypeState(historyData.getWindDeg(), DEGREE_ANGLE);
break;
case CHANNEL_GUST_SPEED:
state = getQuantityTypeState(historyData.getWindGust(), METRE_PER_SECOND);
break;
case CHANNEL_CLOUDINESS:
state = getQuantityTypeState(historyData.getClouds(), PERCENT);
break;
case CHANNEL_VISIBILITY:
@Nullable
State tempstate = new QuantityType<>(historyData.getVisibility(), METRE).toUnit(KILO(METRE));
state = (tempstate == null ? state : tempstate);
case CHANNEL_RAIN:
Rain rain = historyData.getRain();
state = getQuantityTypeState(rain == null ? 0 : rain.get1h(), MILLI(METRE));
break;
case CHANNEL_SNOW:
Snow snow = historyData.getSnow();
state = getQuantityTypeState(snow == null ? 0 : snow.get1h(), MILLI(METRE));
break;
default:
// This should not happen
logger.warn("Unknown channel id {} in onecall hourly weather data", channelId);
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);
}
}
}

View File

@@ -88,4 +88,40 @@
</parameter>
</config-description>
<config-description uri="thing-type:openweathermap:onecall">
<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="0" max="8" step="1">
<label>Number of Days</label>
<description>Number of days for daily forecast, including the current day.</description>
<default>6</default>
</parameter>
<parameter name="forecastHours" type="integer" min="0" max="48" step="1">
<label>Number of Hours</label>
<description>Number of hours for hourly forecast.</description>
<default>12</default>
</parameter>
<parameter name="forecastMinutes" type="integer" min="0" max="60" step="1">
<label>Number of Minutes</label>
<description>Number of minutes for minutely precipitation forecast.</description>
<default>0</default>
</parameter>
</config-description>
<config-description uri="thing-type:openweathermap:onecall-history">
<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="historyDay" type="integer" min="1" max="5" step="1">
<label>History Day</label>
<description>Relative number of days in the past for historical data.</description>
<default>1</default>
</parameter>
</config-description>
</config-description:config-descriptions>

View File

@@ -10,6 +10,10 @@ offline.conf-error-not-supported-number-of-hours = The 'forecastHours' parameter
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.
offline.conf-error-not-supported-onecall-number-of-minutes = The 'forecastMinutes' parameter must be between 0 and 60.
offline.conf-error-not-supported-onecall-number-of-hours = The 'forecastHours' parameter must be between 0 and 48.
offline.conf-error-not-supported-onecall-number-of-days = The 'forecastDays' parameter must be between 0 and 7.
# discovery result
discovery.openweathermap.weather-and-forecast.api.local.label = Local Weather And Forecast
discovery.openweathermap.uvindex.api.local.label = Local UV Index

View File

@@ -258,6 +258,10 @@ offline.conf-error-not-supported-number-of-hours = Der Parameter 'forecastHours'
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.
offline.conf-error-not-supported-onecall-number-of-minutes = Der Parameter 'forecastMinutes' muss zwischen 0 and 60 liegen.
offline.conf-error-not-supported-onecall-number-of-hours = Der Parameter 'forecastHours' muss zwischen 0 und 48 liegen.
offline.conf-error-not-supported-onecall-number-of-days = Der Parameter 'forecastDays' muss zwischen 0 und 7 liegen.
# discovery result
discovery.openweathermap.weather-and-forecast.api.local.label = Lokales Wetter und Wettervorhersage
discovery.openweathermap.uvindex.api.local.label = Lokaler UV-Index

View File

@@ -252,6 +252,10 @@ offline.conf-error-not-supported-number-of-hours = Le param
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.
offline.conf-error-not-supported-onecall-number-of-minutes = Le paramètre 'forecastMinutes' doit être compris entre 0 et 60.
offline.conf-error-not-supported-onecall-number-of-hours = Le paramètre 'forecastHours' doit être compris entre 0 et 48.
offline.conf-error-not-supported-onecall-number-of-days = Le paramètre 'forecastDays' doit être compris entre 0 et 7.
# 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

View File

@@ -105,6 +105,155 @@
</channels>
</channel-group-type>
<channel-group-type id="oneCallCurrent">
<label>One Call API Current Weather</label>
<description>Current weather data from the One Call API.</description>
<channels>
<channel id="time-stamp" typeId="time-stamp"/>
<channel id="sunrise" typeId="sunrise"/>
<channel id="sunset" typeId="sunset"/>
<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="dew-point" typeId="dew-point"/>
<channel id="uvindex" typeId="uvindex"/>
<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="oneCallMinutely">
<label>One Call API Minutely Forecast</label>
<description>Minutely precipitation delivered by the One Call API.</description>
<channels>
<channel id="time-stamp" typeId="time-stamp"/>
<channel id="precipitation" typeId="precipitation"/>
</channels>
</channel-group-type>
<channel-group-type id="oneCallHourly">
<label>One Call API Hourly Forecast</label>
<description>Hourly weather forecast delivered by the One Call API.</description>
<channels>
<channel id="time-stamp" typeId="hourly-forecast-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="dew-point" typeId="dew-point"/>
<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="precip-probability" typeId="precip-probability"/>
<channel id="rain" typeId="rain"/>
<channel id="snow" typeId="snow"/>
<channel id="visibility" typeId="visibility"/>
</channels>
</channel-group-type>
<channel-group-type id="oneCallDaily">
<label>One Call API Daily Forecast</label>
<description>Daily weather forecast delivered by the One Call API.</description>
<channels>
<channel id="time-stamp" typeId="daily-forecast-time-stamp"/>
<channel id="sunrise" typeId="sunrise"/>
<channel id="sunset" typeId="sunset"/>
<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="morning-temperature" typeId="morning-temperature"/>
<channel id="day-temperature" typeId="day-temperature"/>
<channel id="evening-temperature" typeId="evening-temperature"/>
<channel id="night-temperature" typeId="night-temperature"/>
<channel id="min-temperature" typeId="forecasted-min-outdoor-temperature"/>
<channel id="max-temperature" typeId="forecasted-max-outdoor-temperature"/>
<channel id="apparent-morning" typeId="apparent-morning"/>
<channel id="apparent-day" typeId="apparent-day"/>
<channel id="apparent-evening" typeId="apparent-evening"/>
<channel id="apparent-night" typeId="apparent-night"/>
<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="uvindex" typeId="forecasted-uvindex"/>
<channel id="precip-probability" typeId="precip-probability"/>
<channel id="rain" typeId="rain"/>
<channel id="snow" typeId="snow"/>
<channel id="visibility" typeId="visibility"/>
</channels>
</channel-group-type>
<channel-group-type id="oneCallHistory">
<label>One Call API Historical Weather</label>
<description>Historical weather data from the One Call API at this point in time the given day.</description>
<channels>
<channel id="time-stamp" typeId="time-stamp"/>
<channel id="sunrise" typeId="sunrise"/>
<channel id="sunset" typeId="sunset"/>
<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="dew-point" typeId="dew-point"/>
<channel id="uvindex" typeId="uvindex"/>
<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="oneCallHistoryHours">
<label>One Call API Hourly Historical Weather Data</label>
<description>Historical weather data from the One Call API per hour.</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="dew-point" typeId="dew-point"/>
<channel id="uvindex" typeId="uvindex"/>
<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>
<!-- Channels for OpenWeatherMap Binding -->
<channel-type id="station-id">
<item-type>String</item-type>
@@ -128,6 +277,22 @@
<state readOnly="true" pattern="%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS"/>
</channel-type>
<channel-type id="sunrise">
<item-type>DateTime</item-type>
<label>Sunrise Time</label>
<description>Time of sunrise for the given day.</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="sunset">
<item-type>DateTime</item-type>
<label>Sunset Time</label>
<description>Time of sunset for the given day.</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>
@@ -205,6 +370,38 @@
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>
<channel-type id="day-temperature">
<item-type>Number:Temperature</item-type>
<label>Day Temperature</label>
<description>Forecasted outdoor temperature for the day.</description>
<category>Temperature</category>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>
<channel-type id="morning-temperature">
<item-type>Number:Temperature</item-type>
<label>Morning Temperature</label>
<description>Forecasted outdoor temperature for the morning.</description>
<category>Temperature</category>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>
<channel-type id="evening-temperature">
<item-type>Number:Temperature</item-type>
<label>Evening Temperature</label>
<description>Forecasted outdoor temperature for the evening.</description>
<category>Temperature</category>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>
<channel-type id="night-temperature">
<item-type>Number:Temperature</item-type>
<label>Night Temperature</label>
<description>Forecasted outdoor temperature for the night.</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>
@@ -213,6 +410,54 @@
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>
<channel-type id="apparent-morning">
<item-type>Number:Temperature</item-type>
<label>Apparent Morning Temperature</label>
<description>Forecasted apparent temperature in the morning.</description>
<category>Temperature</category>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>
<channel-type id="apparent-day">
<item-type>Number:Temperature</item-type>
<label>Apparent Day Temperature</label>
<description>Forecasted apparent temperature during the day.</description>
<category>Temperature</category>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>
<channel-type id="apparent-evening">
<item-type>Number:Temperature</item-type>
<label>Apparent Evening Temperature</label>
<description>Forecasted apparent temperature at the evening.</description>
<category>Temperature</category>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>
<channel-type id="apparent-night">
<item-type>Number:Temperature</item-type>
<label>Apparent Night Temperature</label>
<description>Forecasted apparent temperature in the night.</description>
<category>Temperature</category>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>
<channel-type id="dew-point" advanced="true">
<item-type>Number:Temperature</item-type>
<label>Dew-Point Temperature</label>
<description>Forecasted dew-point temperature.</description>
<category>Temperature</category>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>
<channel-type id="precipitation">
<item-type>Number:Length</item-type>
<label>Precipitation</label>
<description>Precipitation volume of the related timespan.</description>
<category>Precipitation</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="forecasted-apparent-temperature">
<item-type>Number:Temperature</item-type>
<label>Forecasted Apparent Temperature</label>
@@ -338,4 +583,11 @@
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>
<channel-type id="precip-probability">
<item-type>Number:Dimensionless</item-type>
<label>Probability</label>
<description>Forecasted precipitation probability.</description>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>
</thing:thing-descriptions>

View File

@@ -116,4 +116,183 @@
<config-description-ref uri="thing-type:openweathermap:uvindex"/>
</thing-type>
<thing-type id="onecall">
<supported-bridge-type-refs>
<bridge-type-ref id="weather-api"/>
</supported-bridge-type-refs>
<label>One Call API Weather and Forecast</label>
<description>Provides current weather and forecast data from the OpenWeatherMap One Call API.</description>
<channel-groups>
<channel-group id="current" typeId="oneCallCurrent"/>
<channel-group id="forecastMinutes01" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes02" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes03" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes04" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes05" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes06" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes07" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes08" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes09" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes10" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes11" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes12" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes13" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes14" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes15" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes16" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes17" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes18" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes19" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes20" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes21" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes22" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes23" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes24" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes25" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes26" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes27" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes28" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes29" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes30" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes31" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes32" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes33" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes34" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes35" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes36" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes37" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes38" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes39" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes40" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes41" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes42" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes43" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes44" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes45" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes46" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes47" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes48" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes49" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes50" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes51" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes52" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes53" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes54" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes55" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes56" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes57" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes58" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes59" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes60" typeId="oneCallMinutely"/>
<channel-group id="forecastHours01" typeId="oneCallHourly"/>
<channel-group id="forecastHours02" typeId="oneCallHourly"/>
<channel-group id="forecastHours03" typeId="oneCallHourly"/>
<channel-group id="forecastHours04" typeId="oneCallHourly"/>
<channel-group id="forecastHours05" typeId="oneCallHourly"/>
<channel-group id="forecastHours06" typeId="oneCallHourly"/>
<channel-group id="forecastHours07" typeId="oneCallHourly"/>
<channel-group id="forecastHours08" typeId="oneCallHourly"/>
<channel-group id="forecastHours09" typeId="oneCallHourly"/>
<channel-group id="forecastHours10" typeId="oneCallHourly"/>
<channel-group id="forecastHours11" typeId="oneCallHourly"/>
<channel-group id="forecastHours12" typeId="oneCallHourly"/>
<channel-group id="forecastHours13" typeId="oneCallHourly"/>
<channel-group id="forecastHours14" typeId="oneCallHourly"/>
<channel-group id="forecastHours15" typeId="oneCallHourly"/>
<channel-group id="forecastHours16" typeId="oneCallHourly"/>
<channel-group id="forecastHours17" typeId="oneCallHourly"/>
<channel-group id="forecastHours18" typeId="oneCallHourly"/>
<channel-group id="forecastHours19" typeId="oneCallHourly"/>
<channel-group id="forecastHours20" typeId="oneCallHourly"/>
<channel-group id="forecastHours21" typeId="oneCallHourly"/>
<channel-group id="forecastHours22" typeId="oneCallHourly"/>
<channel-group id="forecastHours23" typeId="oneCallHourly"/>
<channel-group id="forecastHours24" typeId="oneCallHourly"/>
<channel-group id="forecastToday" typeId="oneCallDaily">
<label>One Call API Todays Forecast</label>
<description>This is the weather forecast for today from the one call API.</description>
</channel-group>
<channel-group id="forecastTomorrow" typeId="oneCallDaily">
<label>One Call API Tomorrows Forecast</label>
<description>This is the weather forecast for tomorrow from the one call API.</description>
</channel-group>
<channel-group id="forecastDay2" typeId="oneCallDaily">
<label>One Call API 2 Day Forecast</label>
<description>This is the weather forecast in two days from the one call API.</description>
</channel-group>
<channel-group id="forecastDay3" typeId="oneCallDaily">
<label>One Call API 3 Day Forecast</label>
<description>This is the weather forecast in three days from the one call API.</description>
</channel-group>
<channel-group id="forecastDay4" typeId="oneCallDaily">
<label>One Call API 4 Day Forecast</label>
<description>This is the weather forecast in four days from the one call API.</description>
</channel-group>
<channel-group id="forecastDay5" typeId="oneCallDaily">
<label>One Call API 5 Day Forecast</label>
<description>This is the weather forecast in five days from the one call API.</description>
</channel-group>
<channel-group id="forecastDay6" typeId="oneCallDaily">
<label>One Call API 6 Day Forecast</label>
<description>This is the weather forecast in six days from the one call API.</description>
</channel-group>
<channel-group id="forecastDay7" typeId="oneCallDaily">
<label>One Call API 7 Day Forecast</label>
<description>This is the weather forecast in seven days from the one call API.</description>
</channel-group>
</channel-groups>
<representation-property>location</representation-property>
<config-description-ref uri="thing-type:openweathermap:onecall"/>
</thing-type>
<thing-type id="onecall-history">
<supported-bridge-type-refs>
<bridge-type-ref id="weather-api"/>
</supported-bridge-type-refs>
<label>One Call API Historical data</label>
<description>Provides historical weather data from the OpenWeatherMap One Call API.</description>
<channel-groups>
<channel-group id="history" typeId="oneCallHistory"/>
<channel-group id="historyHours01" typeId="oneCallHistoryHours"/>
<channel-group id="historyHours02" typeId="oneCallHistoryHours"/>
<channel-group id="historyHours03" typeId="oneCallHistoryHours"/>
<channel-group id="historyHours04" typeId="oneCallHistoryHours"/>
<channel-group id="historyHours05" typeId="oneCallHistoryHours"/>
<channel-group id="historyHours06" typeId="oneCallHistoryHours"/>
<channel-group id="historyHours07" typeId="oneCallHistoryHours"/>
<channel-group id="historyHours08" typeId="oneCallHistoryHours"/>
<channel-group id="historyHours09" typeId="oneCallHistoryHours"/>
<channel-group id="historyHours10" typeId="oneCallHistoryHours"/>
<channel-group id="historyHours11" typeId="oneCallHistoryHours"/>
<channel-group id="historyHours12" typeId="oneCallHistoryHours"/>
<channel-group id="historyHours13" typeId="oneCallHistoryHours"/>
<channel-group id="historyHours14" typeId="oneCallHistoryHours"/>
<channel-group id="historyHours15" typeId="oneCallHistoryHours"/>
<channel-group id="historyHours16" typeId="oneCallHistoryHours"/>
<channel-group id="historyHours17" typeId="oneCallHistoryHours"/>
<channel-group id="historyHours18" typeId="oneCallHistoryHours"/>
<channel-group id="historyHours19" typeId="oneCallHistoryHours"/>
<channel-group id="historyHours20" typeId="oneCallHistoryHours"/>
<channel-group id="historyHours21" typeId="oneCallHistoryHours"/>
<channel-group id="historyHours22" typeId="oneCallHistoryHours"/>
<channel-group id="historyHours23" typeId="oneCallHistoryHours"/>
<channel-group id="historyHours24" typeId="oneCallHistoryHours"/>
</channel-groups>
<representation-property>location</representation-property>
<config-description-ref uri="thing-type:openweathermap:onecall-history"/>
</thing-type>
</thing:thing-descriptions>