From b1e48e0db9c8710f94da44dbab35e41cff18b1e0 Mon Sep 17 00:00:00 2001 From: Christoph Weitkamp Date: Sat, 27 Mar 2021 20:04:02 +0100 Subject: [PATCH] [openweathermap] Added support for Air Pollution API (#10343) Signed-off-by: Christoph Weitkamp --- .../README.md | 42 ++- .../OpenWeatherMapBindingConstants.java | 13 + ...enWeatherMapAirPollutionConfiguration.java | 27 ++ .../connection/OpenWeatherMapConnection.java | 46 ++- .../OpenWeatherMapDiscoveryService.java | 7 + .../OpenWeatherMapJsonAirPollutionData.java | 26 ++ .../internal/dto/airpollution/Components.java | 39 +++ .../internal/dto/airpollution/List.java | 28 ++ .../internal/dto/airpollution/Main.java | 25 ++ .../internal/dto/forecast/daily/List.java | 27 ++ .../factory/OpenWeatherMapHandlerFactory.java | 15 +- .../AbstractOpenWeatherMapHandler.java | 9 +- .../handler/OpenWeatherMapAPIHandler.java | 8 +- .../OpenWeatherMapAirPollutionHandler.java | 262 ++++++++++++++++++ ...enWeatherMapWeatherAndForecastHandler.java | 10 + .../main/resources/OH-INF/config/config.xml | 13 + .../OH-INF/i18n/openweathermap_de.properties | 92 ++++++ .../resources/OH-INF/thing/channel-types.xml | 183 +++++++++++- .../resources/OH-INF/thing/thing-types.xml | 17 ++ 19 files changed, 866 insertions(+), 23 deletions(-) create mode 100644 bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/config/OpenWeatherMapAirPollutionConfiguration.java create mode 100644 bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/dto/OpenWeatherMapJsonAirPollutionData.java create mode 100644 bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/dto/airpollution/Components.java create mode 100644 bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/dto/airpollution/List.java create mode 100644 bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/dto/airpollution/Main.java create mode 100644 bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/handler/OpenWeatherMapAirPollutionHandler.java diff --git a/bundles/org.openhab.binding.openweathermap/README.md b/bundles/org.openhab.binding.openweathermap/README.md index 69510989c5e..d63422b117a 100644 --- a/bundles/org.openhab.binding.openweathermap/README.md +++ b/bundles/org.openhab.binding.openweathermap/README.md @@ -10,7 +10,7 @@ This binding integrates the [OpenWeatherMap weather API](https://openweathermap. ## Supported Things -There are five supported things. +There are six supported things. ### OpenWeatherMap Account @@ -38,6 +38,13 @@ The third thing `uvindex` supports the [current UV Index](https://openweathermap It requires coordinates of the location of your interest. You can add as much `uvindex` things for different locations to your setup as you like to observe. +### Current And Forecasted Air Pollution + +Another thing is the `air-pollution` which provides the [current air pollution](https://openweathermap.org/api/air-pollution) and [forecasted air pollution](https://openweathermap.org/api/air-pollution#forecast) for a specific location. +It requires coordinates of the location of your interest. +Air pollution forecast is available for 5 days with hourly granularity. +You can add as much `air-pollution` things for different locations to your setup as you like to observe. + ### One Call API Weather and Forecast The thing `onecall` supports the [current and forecast weather data](https://openweathermap.org/api/one-call-api#how) for a specific location using the One Call API. @@ -78,13 +85,22 @@ Once the parameters `forecastHours` or `forecastDays` will be changed, the avail ### Current UV Index And Forecast -| Parameter | Description | -|----------------|--------------------------------------------------------------------------------------------------------------------------------| -| location | Location of weather in geographical coordinates (latitude/longitude/altitude). **Mandatory** | +| Parameter | Description | +|----------------|----------------------------------------------------------------------------------------------------------------------------------| +| location | Location of weather in geographical coordinates (latitude/longitude/altitude). **Mandatory** | | forecastDays | Number of days for UV Index forecast (including todays forecast). Optional, the default value is 6 (min="1", max="8", step="1"). | Once the parameter `forecastDays` will be changed, the available channel groups on the thing will be created or removed accordingly. +### Current Air Pollution And Forecast + +| Parameter | Description | +|----------------|--------------------------------------------------------------------------------------------------------------------------------| +| location | Location of weather in geographical coordinates (latitude/longitude/altitude). **Mandatory** | +| forecastHours | Number of hours for air pollution forecast. Optional, the default value is 0 (min="0", max="120", step="1"). | + +Once the parameter `forecastHours` will be changed, the available channel groups on the thing will be created or removed accordingly. + ### One Call API Weather and Forecast | Parameter | Description | @@ -188,6 +204,8 @@ See above for a description of the available channels. | Channel Group ID | Channel ID | Item Type | Description | |------------------------------------------------------------------|----------------------|----------------------|-----------------------------------------------------------------------------------| | forecastToday, forecastTomorrow, forecastDay2, ... forecastDay16 | time-stamp | DateTime | Date of data forecasted. | +| forecastToday, forecastTomorrow, forecastDay2, ... forecastDay16 | sunrise | DateTime | Time of sunrise for the given day. | +| forecastToday, forecastTomorrow, forecastDay2, ... forecastDay16 | sunset | DateTime | Time of sunset for the given day. | | forecastToday, forecastTomorrow, forecastDay2, ... forecastDay16 | condition | String | Forecast weather condition. | | forecastToday, forecastTomorrow, forecastDay2, ... forecastDay16 | condition-id | String | Id of the forecasted weather condition. **Advanced** | | forecastToday, forecastTomorrow, forecastDay2, ... forecastDay16 | icon | Image | Icon representing the forecasted weather condition. | @@ -205,6 +223,7 @@ See above for a description of the available channels. | forecastToday, forecastTomorrow, forecastDay2, ... forecastDay16 | snow | Number:Length | Expected snow volume of a day. | | forecastToday, forecastTomorrow, forecastDay2, ... forecastDay7 | dew-point | Number:Temperature | Expected dew-point. Only available in the One Call API | | forecastToday, forecastTomorrow, forecastDay2, ... forecastDay7 | uvindex | Number | Forecasted Midday UV Index. Only available in the One Call API | +| forecastToday, forecastTomorrow, forecastDay2, ... forecastDay7 | precip-probability | Number:Dimensionless | Precipitation probability. | | forecastToday, forecastTomorrow, forecastDay2, ... forecastDay7 | morning-temperature | Number:Temperature | Expected morning temperature. Only available in the One Call API | | forecastToday, forecastTomorrow, forecastDay2, ... forecastDay7 | day-temperature | Number:Temperature | Expected day-temperature. Only available in the One Call API | | forecastToday, forecastTomorrow, forecastDay2, ... forecastDay7 | evening-temperature | Number:Temperature | Expected evening-temperature. Only available in the One Call API | @@ -223,6 +242,21 @@ See above for a description of the available channels. The `uvindex` channel is also available in the current data and the daily forecast of the One Call API. +### Air Pollution + +| Channel Group ID | Channel ID | Item Type | Description | +|-----------------------------------------------------------------|------------------------|----------------|--------------------------------------------------------------------------| +| current, forecastHours01, forecastHours02, ... forecastHours120 | time-stamp | DateTime | Date of data observation / forecast. | +| current, forecastHours01, forecastHours02, ... forecastHours120 | airQualityIndex | Number | Current or forecasted air quality index. | +| current, forecastHours01, forecastHours02, ... forecastHours120 | particulateMatter2dot5 | Number:Density | Current or forecasted density of particles less than 2.5 µm in diameter. | +| current, forecastHours01, forecastHours02, ... forecastHours120 | particulateMatter10 | Number:Density | Current or forecasted density of particles less than 10 µm in diameter. | +| current, forecastHours01, forecastHours02, ... forecastHours120 | carbonMonoxide | Number:Density | Current or forecasted concentration of carbon monoxide. | +| current, forecastHours01, forecastHours02, ... forecastHours120 | nitrogenMonoxide | Number:Density | Current or forecasted concentration of nitrogen monoxide. | +| current, forecastHours01, forecastHours02, ... forecastHours120 | nitrogenDioxide | Number:Density | Current or forecasted concentration of nitrogen dioxide. | +| current, forecastHours01, forecastHours02, ... forecastHours120 | ozone | Number:Density | Current or forecasted concentration of ozone. | +| current, forecastHours01, forecastHours02, ... forecastHours120 | sulphurDioxide | Number:Density | Current or forecasted concentration of sulphur dioxide. | +| current, forecastHours01, forecastHours02, ... forecastHours120 | ammonia | Number:Density | Current or forecasted concentration of ammonia. | + ## Full Example ### Things diff --git a/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/OpenWeatherMapBindingConstants.java b/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/OpenWeatherMapBindingConstants.java index ea3c6afad96..3a72a1908b6 100644 --- a/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/OpenWeatherMapBindingConstants.java +++ b/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/OpenWeatherMapBindingConstants.java @@ -36,6 +36,7 @@ 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"); + public static final ThingTypeUID THING_TYPE_AIR_POLLUTION = new ThingTypeUID(BINDING_ID, "air-pollution"); // One Call API forecast public static final ThingTypeUID THING_TYPE_ONECALL_WEATHER_AND_FORECAST = new ThingTypeUID(BINDING_ID, "onecall"); // One Call API historical data @@ -54,6 +55,8 @@ public class OpenWeatherMapBindingConstants { "dailyForecast"); public static final ChannelGroupTypeUID CHANNEL_GROUP_TYPE_UVINDEX_FORECAST = new ChannelGroupTypeUID(BINDING_ID, "uvindexForecast"); + public static final ChannelGroupTypeUID CHANNEL_GROUP_TYPE_AIR_POLLUTION_FORECAST = new ChannelGroupTypeUID( + BINDING_ID, "airPollutionForecast"); 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( @@ -69,6 +72,7 @@ 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_CURRENT_AIR_POLLUTION = "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"; @@ -109,6 +113,15 @@ public class OpenWeatherMapBindingConstants { 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_AIR_QUALITY_INDEX = "airQualityIndex"; + public static final String CHANNEL_PARTICULATE_MATTER_2_5 = "particulateMatter2dot5"; + public static final String CHANNEL_PARTICULATE_MATTER_10 = "particulateMatter10"; + public static final String CHANNEL_CARBON_MONOXIDE = "carbonMonoxide"; + public static final String CHANNEL_NITROGEN_MONOXIDE = "nitrogenMonoxide"; + public static final String CHANNEL_NITROGEN_DIOXIDE = "nitrogenDioxide"; + public static final String CHANNEL_OZONE = "ozone"; + public static final String CHANNEL_SULPHUR_DIOXIDE = "sulphurDioxide"; + public static final String CHANNEL_AMMONIA = "ammonia"; public static final String CHANNEL_PRECIPITATION = "precipitation"; // List of all configuration diff --git a/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/config/OpenWeatherMapAirPollutionConfiguration.java b/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/config/OpenWeatherMapAirPollutionConfiguration.java new file mode 100644 index 00000000000..7068b1c7f04 --- /dev/null +++ b/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/config/OpenWeatherMapAirPollutionConfiguration.java @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.openweathermap.internal.config; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.openweathermap.internal.handler.OpenWeatherMapAirPollutionHandler; + +/** + * The {@link OpenWeatherMapAirPollutionConfiguration} is the class used to match the + * {@link OpenWeatherMapAirPollutionHandler}s configuration. + * + * @author Christoph Weitkamp - Initial contribution + */ +@NonNullByDefault +public class OpenWeatherMapAirPollutionConfiguration extends OpenWeatherMapLocationConfiguration { + public int forecastHours; +} diff --git a/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/connection/OpenWeatherMapConnection.java b/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/connection/OpenWeatherMapConnection.java index a0bb9bcc871..db25ed9fac3 100644 --- a/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/connection/OpenWeatherMapConnection.java +++ b/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/connection/OpenWeatherMapConnection.java @@ -35,6 +35,7 @@ import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.HttpResponseException; import org.eclipse.jetty.client.api.ContentResponse; import org.openhab.binding.openweathermap.internal.config.OpenWeatherMapAPIConfiguration; +import org.openhab.binding.openweathermap.internal.dto.OpenWeatherMapJsonAirPollutionData; import org.openhab.binding.openweathermap.internal.dto.OpenWeatherMapJsonDailyForecastData; import org.openhab.binding.openweathermap.internal.dto.OpenWeatherMapJsonHourlyForecastData; import org.openhab.binding.openweathermap.internal.dto.OpenWeatherMapJsonUVIndexData; @@ -88,6 +89,9 @@ public class OpenWeatherMapConnection { // UV Index (see https://openweathermap.org/api/uvi) private static final String UVINDEX_URL = "https://api.openweathermap.org/data/2.5/uvi"; private static final String UVINDEX_FORECAST_URL = "https://api.openweathermap.org/data/2.5/uvi/forecast"; + // Air Pollution (see https://openweathermap.org/api/air-pollution) + private static final String AIR_POLLUTION_URL = "https://api.openweathermap.org/data/2.5/air_pollution"; + private static final String AIR_POLLUTION_FORECAST_URL = "https://api.openweathermap.org/data/2.5/air_pollution/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 ) @@ -176,7 +180,7 @@ public class OpenWeatherMapConnection { } /** - * Requests the UV Index data for the given location (see https://api.openweathermap.org/data/2.5/uvi). + * Requests the UV Index data for the given location (see https://openweathermap.org/api/uvi). * * @param location location represented as {@link PointType} * @return the UV Index data @@ -193,7 +197,7 @@ public class OpenWeatherMapConnection { } /** - * Requests the UV Index forecast data for the given location (see https://api.openweathermap.org/data/2.5/uvi). + * Requests the UV Index forecast data for the given location (see https://openweathermap.org/api/uvi). * * @param location location represented as {@link PointType} * @return the UV Index forecast data @@ -216,6 +220,42 @@ public class OpenWeatherMapConnection { OpenWeatherMapJsonUVIndexData[].class)); } + /** + * Requests the Air Pollution data for the given location (see https://openweathermap.org/api/air-pollution). + * + * @param location location represented as {@link PointType} + * @return the Air Pollution data + * @throws JsonSyntaxException + * @throws OpenWeatherMapCommunicationException + * @throws OpenWeatherMapConfigurationException + */ + public synchronized @Nullable OpenWeatherMapJsonAirPollutionData getAirPollutionData(@Nullable PointType location) + throws JsonSyntaxException, OpenWeatherMapCommunicationException, OpenWeatherMapConfigurationException { + return gson.fromJson( + getResponseFromCache( + buildURL(AIR_POLLUTION_URL, getRequestParams(handler.getOpenWeatherMapAPIConfig(), location))), + OpenWeatherMapJsonAirPollutionData.class); + } + + /** + * Requests the Air Pollution forecast data for the given location (see + * https://openweathermap.org/api/air-pollution). + * + * @param location location represented as {@link PointType} + * @return the Air Pollution forecast data + * @throws JsonSyntaxException + * @throws OpenWeatherMapCommunicationException + * @throws OpenWeatherMapConfigurationException + */ + public synchronized @Nullable OpenWeatherMapJsonAirPollutionData getAirPollutionForecastData( + @Nullable PointType location) + throws JsonSyntaxException, OpenWeatherMapCommunicationException, OpenWeatherMapConfigurationException { + return gson.fromJson( + getResponseFromCache(buildURL(AIR_POLLUTION_FORECAST_URL, + getRequestParams(handler.getOpenWeatherMapAPIConfig(), location))), + OpenWeatherMapJsonAirPollutionData.class); + } + /** * Downloads the icon for the given icon id (see https://openweathermap.org/weather-conditions). * @@ -317,7 +357,7 @@ public class OpenWeatherMapConnection { } Map params = new HashMap<>(); - // API key (see http://openweathermap.org/appid) + // API key (see https://openweathermap.org/appid) String apikey = config.apikey; if (apikey == null || (apikey = apikey.trim()).isEmpty()) { throw new OpenWeatherMapConfigurationException("@text/offline.conf-error-missing-apikey"); diff --git a/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/discovery/OpenWeatherMapDiscoveryService.java b/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/discovery/OpenWeatherMapDiscoveryService.java index 04cef9f1a64..70293fe1e22 100644 --- a/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/discovery/OpenWeatherMapDiscoveryService.java +++ b/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/discovery/OpenWeatherMapDiscoveryService.java @@ -129,6 +129,7 @@ public class OpenWeatherMapDiscoveryService extends AbstractDiscoveryService { String locationString = location.toFullString(); ThingUID bridgeUID = bridgeHandler.getThing().getUID(); createWeatherAndForecastResult(locationString, bridgeUID); + createAirPollutionResult(locationString, bridgeUID); createOneCallResult(locationString, bridgeUID); createOneCallHistoryResult(locationString, bridgeUID); } @@ -139,6 +140,12 @@ public class OpenWeatherMapDiscoveryService extends AbstractDiscoveryService { .withRepresentationProperty(CONFIG_LOCATION).withBridge(bridgeUID).build()); } + private void createAirPollutionResult(String location, ThingUID bridgeUID) { + thingDiscovered(DiscoveryResultBuilder.create(new ThingUID(THING_TYPE_AIR_POLLUTION, bridgeUID, LOCAL)) + .withLabel("Local Air Pollution").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)) diff --git a/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/dto/OpenWeatherMapJsonAirPollutionData.java b/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/dto/OpenWeatherMapJsonAirPollutionData.java new file mode 100644 index 00000000000..f7230e456ac --- /dev/null +++ b/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/dto/OpenWeatherMapJsonAirPollutionData.java @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.openweathermap.internal.dto; + +import org.openhab.binding.openweathermap.internal.dto.base.Coord; + +/** + * The {@link OpenWeatherMapJsonAirPollutionData} is the Java class used to map the JSON response to an OpenWeatherMap + * request. + * + * @author Christoph Weitkamp - Initial contribution + */ +public class OpenWeatherMapJsonAirPollutionData { + public Coord coord; + public java.util.List list; +} diff --git a/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/dto/airpollution/Components.java b/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/dto/airpollution/Components.java new file mode 100644 index 00000000000..3c20083f329 --- /dev/null +++ b/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/dto/airpollution/Components.java @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2010-2021 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.airpollution; + +import com.google.gson.annotations.SerializedName; + +/** + * Generated Plain Old Java Objects class for {@link Components} from JSON. + * + * @author Christoph Weitkamp - Initial contribution + */ +public class Components { + @SerializedName("co") + public double carbonMonoxide; + @SerializedName("no") + public double nitrogenMonoxide; + @SerializedName("no2") + public double nitrogenDioxide; + @SerializedName("o2") + public double ozone; + @SerializedName("so2") + public double sulphurDioxide; + @SerializedName("pm2_5") + public double particulateMatter2dot5; + @SerializedName("pm10") + public double particulateMatter10; + @SerializedName("nh3") + public double ammonia; +} diff --git a/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/dto/airpollution/List.java b/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/dto/airpollution/List.java new file mode 100644 index 00000000000..f0e239395c5 --- /dev/null +++ b/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/dto/airpollution/List.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2010-2021 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.airpollution; + +import com.google.gson.annotations.SerializedName; + +/** + * Generated Plain Old Java Objects class for {@link List} from JSON. + * + * @author Christoph Weitkamp - Initial contribution + */ +public class List { + public int dt; + @SerializedName("main") + public Main airQualityIndex; + @SerializedName("components") + public Components measurements; +} diff --git a/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/dto/airpollution/Main.java b/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/dto/airpollution/Main.java new file mode 100644 index 00000000000..d25c965b0fe --- /dev/null +++ b/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/dto/airpollution/Main.java @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2010-2021 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.airpollution; + +import com.google.gson.annotations.SerializedName; + +/** + * Generated Plain Old Java Objects class for {@link Main} from JSON. + * + * @author Christoph Weitkamp - Initial contribution + */ +public class Main { + @SerializedName("aqi") + public int index; +} diff --git a/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/dto/forecast/daily/List.java b/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/dto/forecast/daily/List.java index a6dbe74eed3..63f18b5b375 100644 --- a/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/dto/forecast/daily/List.java +++ b/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/dto/forecast/daily/List.java @@ -24,6 +24,8 @@ import com.google.gson.annotations.SerializedName; */ public class List { private Integer dt; + private @Nullable Integer sunrise; + private @Nullable Integer sunset; private Temp temp; @SerializedName("feels_like") private @Nullable FeelsLikeTemp feelsLikeTemp; @@ -36,6 +38,7 @@ public class List { private Integer clouds; private @Nullable Double rain; private @Nullable Double snow; + private @Nullable Double pop; public Integer getDt() { return dt; @@ -45,6 +48,22 @@ public class List { this.dt = dt; } + public @Nullable Integer getSunrise() { + return sunrise; + } + + public void setSunrise(Integer sunrise) { + this.sunrise = sunrise; + } + + public @Nullable Integer getSunset() { + return sunset; + } + + public void setSunset(Integer sunset) { + this.sunset = sunset; + } + public Temp getTemp() { return temp; } @@ -132,4 +151,12 @@ public class List { public void setSnow(Double snow) { this.snow = snow; } + + public @Nullable Double getPop() { + return pop; + } + + public void setPop(Double pop) { + this.pop = pop; + } } diff --git a/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/factory/OpenWeatherMapHandlerFactory.java b/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/factory/OpenWeatherMapHandlerFactory.java index df137ce069c..a2aa8fac6e2 100644 --- a/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/factory/OpenWeatherMapHandlerFactory.java +++ b/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/factory/OpenWeatherMapHandlerFactory.java @@ -16,7 +16,6 @@ import static org.openhab.binding.openweathermap.internal.OpenWeatherMapBindingC import java.util.Collections; import java.util.HashMap; -import java.util.Hashtable; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; @@ -26,7 +25,13 @@ 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.*; +import org.openhab.binding.openweathermap.internal.handler.AbstractOpenWeatherMapHandler; +import org.openhab.binding.openweathermap.internal.handler.OpenWeatherMapAPIHandler; +import org.openhab.binding.openweathermap.internal.handler.OpenWeatherMapAirPollutionHandler; +import org.openhab.binding.openweathermap.internal.handler.OpenWeatherMapOneCallHandler; +import org.openhab.binding.openweathermap.internal.handler.OpenWeatherMapOneCallHistoryHandler; +import org.openhab.binding.openweathermap.internal.handler.OpenWeatherMapUVIndexHandler; +import org.openhab.binding.openweathermap.internal.handler.OpenWeatherMapWeatherAndForecastHandler; import org.openhab.core.config.discovery.DiscoveryService; import org.openhab.core.i18n.LocaleProvider; import org.openhab.core.i18n.LocationProvider; @@ -90,13 +95,15 @@ public class OpenWeatherMapHandlerFactory extends BaseThingHandlerFactory { // register discovery service OpenWeatherMapDiscoveryService discoveryService = new OpenWeatherMapDiscoveryService(handler, locationProvider, localeProvider, i18nProvider); - discoveryServiceRegs.put(handler.getThing().getUID(), bundleContext - .registerService(DiscoveryService.class.getName(), discoveryService, new Hashtable<>())); + discoveryServiceRegs.put(handler.getThing().getUID(), + bundleContext.registerService(DiscoveryService.class.getName(), discoveryService, null)); return handler; } else if (THING_TYPE_WEATHER_AND_FORECAST.equals(thingTypeUID)) { return new OpenWeatherMapWeatherAndForecastHandler(thing, timeZoneProvider); } else if (THING_TYPE_UVINDEX.equals(thingTypeUID)) { return new OpenWeatherMapUVIndexHandler(thing, timeZoneProvider); + } else if (THING_TYPE_AIR_POLLUTION.equals(thingTypeUID)) { + return new OpenWeatherMapAirPollutionHandler(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)) { diff --git a/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/handler/AbstractOpenWeatherMapHandler.java b/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/handler/AbstractOpenWeatherMapHandler.java index 26b67388ea0..6f3e00b9387 100644 --- a/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/handler/AbstractOpenWeatherMapHandler.java +++ b/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/handler/AbstractOpenWeatherMapHandler.java @@ -17,11 +17,8 @@ import static org.openhab.binding.openweathermap.internal.OpenWeatherMapBindingC import java.time.Instant; import java.time.ZonedDateTime; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; import javax.measure.Unit; @@ -69,9 +66,9 @@ public abstract class AbstractOpenWeatherMapHandler extends BaseThingHandler { private final Logger logger = LoggerFactory.getLogger(AbstractOpenWeatherMapHandler.class); - public static final Set 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())); + public static final Set SUPPORTED_THING_TYPES = Set.of(THING_TYPE_WEATHER_AND_FORECAST, + THING_TYPE_UVINDEX, THING_TYPE_AIR_POLLUTION, THING_TYPE_ONECALL_WEATHER_AND_FORECAST, + THING_TYPE_ONECALL_HISTORY); private final TimeZoneProvider timeZoneProvider; diff --git a/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/handler/OpenWeatherMapAPIHandler.java b/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/handler/OpenWeatherMapAPIHandler.java index 357b9055af3..654d940cfd0 100644 --- a/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/handler/OpenWeatherMapAPIHandler.java +++ b/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/handler/OpenWeatherMapAPIHandler.java @@ -14,7 +14,6 @@ package org.openhab.binding.openweathermap.internal.handler; import static org.openhab.binding.openweathermap.internal.OpenWeatherMapBindingConstants.*; -import java.util.Collections; import java.util.Set; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -34,6 +33,7 @@ import org.openhab.core.thing.ThingStatusDetail; import org.openhab.core.thing.ThingTypeUID; import org.openhab.core.thing.binding.BaseBridgeHandler; import org.openhab.core.thing.binding.ThingHandler; +import org.openhab.core.thing.util.ThingHandlerHelper; import org.openhab.core.types.Command; import org.openhab.core.types.RefreshType; import org.slf4j.Logger; @@ -49,7 +49,7 @@ public class OpenWeatherMapAPIHandler extends BaseBridgeHandler { private final Logger logger = LoggerFactory.getLogger(OpenWeatherMapAPIHandler.class); - public static final Set SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_WEATHER_API); + public static final Set SUPPORTED_THING_TYPES = Set.of(THING_TYPE_WEATHER_API); private static final long INITIAL_DELAY_IN_SECONDS = 15; @@ -74,7 +74,7 @@ public class OpenWeatherMapAPIHandler extends BaseBridgeHandler { config = getConfigAs(OpenWeatherMapAPIConfiguration.class); boolean configValid = true; - if (config.apikey == null || config.apikey.trim().isEmpty()) { + if (config.apikey.isBlank()) { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "@text/offline.conf-error-missing-apikey"); configValid = false; @@ -172,7 +172,7 @@ public class OpenWeatherMapAPIHandler extends BaseBridgeHandler { } private ThingStatus updateThing(@Nullable AbstractOpenWeatherMapHandler handler, Thing thing) { - if (handler != null && connection != null) { + if (handler != null && ThingHandlerHelper.isHandlerInitialized(handler) && connection != null) { handler.updateData(connection); return thing.getStatus(); } else { diff --git a/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/handler/OpenWeatherMapAirPollutionHandler.java b/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/handler/OpenWeatherMapAirPollutionHandler.java new file mode 100644 index 00000000000..b937c3ac842 --- /dev/null +++ b/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/handler/OpenWeatherMapAirPollutionHandler.java @@ -0,0 +1,262 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.openweathermap.internal.handler; + +import static org.openhab.binding.openweathermap.internal.OpenWeatherMapBindingConstants.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.openweathermap.internal.config.OpenWeatherMapAirPollutionConfiguration; +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.OpenWeatherMapJsonAirPollutionData; +import org.openhab.core.i18n.TimeZoneProvider; +import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.unit.Units; +import org.openhab.core.thing.Channel; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingStatus; +import org.openhab.core.thing.ThingStatusDetail; +import org.openhab.core.thing.binding.builder.ThingBuilder; +import org.openhab.core.types.State; +import org.openhab.core.types.UnDefType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonSyntaxException; + +/** + * The {@link OpenWeatherMapAirPollutionHandler} is responsible for handling commands, which are sent to one of the + * channels. + * + * @author Christoph Weitkamp - Initial contribution + */ +@NonNullByDefault +public class OpenWeatherMapAirPollutionHandler extends AbstractOpenWeatherMapHandler { + + private final Logger logger = LoggerFactory.getLogger(OpenWeatherMapAirPollutionHandler.class); + + private static final String CHANNEL_GROUP_HOURLY_FORECAST_PREFIX = "forecastHours"; + private static final Pattern CHANNEL_GROUP_HOURLY_FORECAST_PREFIX_PATTERN = Pattern + .compile(CHANNEL_GROUP_HOURLY_FORECAST_PREFIX + "([0-9]*)"); + + // keeps track of the parsed count + private int forecastHours = 0; + + private @Nullable OpenWeatherMapJsonAirPollutionData airPollutionData; + private @Nullable OpenWeatherMapJsonAirPollutionData airPollutionForecastData; + + public OpenWeatherMapAirPollutionHandler(Thing thing, final TimeZoneProvider timeZoneProvider) { + super(thing, timeZoneProvider); + } + + @Override + public void initialize() { + super.initialize(); + logger.debug("Initialize OpenWeatherMapAirPollutionHandler handler '{}'.", getThing().getUID()); + OpenWeatherMapAirPollutionConfiguration config = getConfigAs(OpenWeatherMapAirPollutionConfiguration.class); + + boolean configValid = true; + int newForecastHours = config.forecastHours; + if (newForecastHours < 0 || newForecastHours > 120) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, + "@text/offline.conf-error-not-supported-air-pollution-number-of-hours"); + configValid = false; + } + + if (configValid) { + logger.debug("Rebuilding thing '{}'.", getThing().getUID()); + List toBeAddedChannels = new ArrayList<>(); + List toBeRemovedChannels = new ArrayList<>(); + if (forecastHours != newForecastHours) { + logger.debug("Rebuilding air pollution channel groups."); + 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_AIR_POLLUTION_FORECAST)); + } + } + forecastHours = newForecastHours; + } + ThingBuilder builder = editThing().withoutChannels(toBeRemovedChannels); + for (Channel channel : toBeAddedChannels) { + builder.withChannel(channel); + } + updateThing(builder.build()); + } + } + + @Override + protected boolean requestData(OpenWeatherMapConnection connection) + throws OpenWeatherMapCommunicationException, OpenWeatherMapConfigurationException { + logger.debug("Update air pollution data of thing '{}'.", getThing().getUID()); + try { + airPollutionData = connection.getAirPollutionData(location); + if (forecastHours > 0) { + airPollutionForecastData = connection.getAirPollutionForecastData(location); + } + return true; + } catch (JsonSyntaxException e) { + logger.debug("JsonSyntaxException occurred during execution: {}", e.getLocalizedMessage(), e); + return false; + } + } + + @Override + protected void updateChannel(ChannelUID channelUID) { + switch (channelUID.getGroupId()) { + case CHANNEL_GROUP_CURRENT_AIR_POLLUTION: + updateCurrentAirPollutionChannel(channelUID); + break; + default: + Matcher m = CHANNEL_GROUP_HOURLY_FORECAST_PREFIX_PATTERN.matcher(channelUID.getGroupId()); + int i; + if (m.find() && (i = Integer.parseInt(m.group(1))) > 0 && i <= 120) { + updateHourlyForecastChannel(channelUID, i); + } + break; + } + } + + /** + * Update the channel from the last OpenWeatherMap data retrieved. + * + * @param channelUID the id identifying the channel to be updated + */ + private void updateCurrentAirPollutionChannel(ChannelUID channelUID) { + String channelId = channelUID.getIdWithoutGroup(); + String channelGroupId = channelUID.getGroupId(); + OpenWeatherMapJsonAirPollutionData localAirPollutionData = airPollutionData; + if (localAirPollutionData != null && !localAirPollutionData.list.isEmpty()) { + org.openhab.binding.openweathermap.internal.dto.airpollution.List currentData = localAirPollutionData.list + .get(0); + State state = UnDefType.UNDEF; + switch (channelId) { + case CHANNEL_TIME_STAMP: + state = getDateTimeTypeState(currentData.dt); + break; + case CHANNEL_AIR_QUALITY_INDEX: + state = new DecimalType(currentData.airQualityIndex.index); + break; + case CHANNEL_PARTICULATE_MATTER_2_5: + state = getQuantityTypeState(currentData.measurements.particulateMatter2dot5, + Units.MICROGRAM_PER_CUBICMETRE); + break; + case CHANNEL_PARTICULATE_MATTER_10: + state = getQuantityTypeState(currentData.measurements.particulateMatter10, + Units.MICROGRAM_PER_CUBICMETRE); + break; + case CHANNEL_CARBON_MONOXIDE: + state = getQuantityTypeState(currentData.measurements.carbonMonoxide, + Units.MICROGRAM_PER_CUBICMETRE); + break; + case CHANNEL_NITROGEN_MONOXIDE: + state = getQuantityTypeState(currentData.measurements.nitrogenMonoxide, + Units.MICROGRAM_PER_CUBICMETRE); + break; + case CHANNEL_NITROGEN_DIOXIDE: + state = getQuantityTypeState(currentData.measurements.nitrogenDioxide, + Units.MICROGRAM_PER_CUBICMETRE); + break; + case CHANNEL_OZONE: + state = getQuantityTypeState(currentData.measurements.ozone, Units.MICROGRAM_PER_CUBICMETRE); + break; + case CHANNEL_SULPHUR_DIOXIDE: + state = getQuantityTypeState(currentData.measurements.sulphurDioxide, + Units.MICROGRAM_PER_CUBICMETRE); + break; + case CHANNEL_AMMONIA: + state = getQuantityTypeState(currentData.measurements.ammonia, Units.MICROGRAM_PER_CUBICMETRE); + break; + } + logger.debug("Update channel '{}' of group '{}' with new state '{}'.", channelId, channelGroupId, state); + updateState(channelUID, state); + } else { + logger.debug("No air pollution data available to update channel '{}' of group '{}'.", channelId, + channelGroupId); + } + } + + /** + * Update the channel from the last OpenWeatherMap data retrieved. + * + * @param channelUID the id identifying the channel to be updated + * @param count + */ + private void updateHourlyForecastChannel(ChannelUID channelUID, int count) { + String channelId = channelUID.getIdWithoutGroup(); + String channelGroupId = channelUID.getGroupId(); + OpenWeatherMapJsonAirPollutionData localAirPollutionForecastData = airPollutionForecastData; + if (localAirPollutionForecastData != null && localAirPollutionForecastData.list.size() >= count) { + org.openhab.binding.openweathermap.internal.dto.airpollution.List forecastData = localAirPollutionForecastData.list + .get(count - 1); + State state = UnDefType.UNDEF; + switch (channelId) { + case CHANNEL_TIME_STAMP: + state = getDateTimeTypeState(forecastData.dt); + break; + case CHANNEL_AIR_QUALITY_INDEX: + state = new DecimalType(forecastData.airQualityIndex.index); + break; + case CHANNEL_PARTICULATE_MATTER_2_5: + state = getQuantityTypeState(forecastData.measurements.particulateMatter2dot5, + Units.MICROGRAM_PER_CUBICMETRE); + break; + case CHANNEL_PARTICULATE_MATTER_10: + state = getQuantityTypeState(forecastData.measurements.particulateMatter10, + Units.MICROGRAM_PER_CUBICMETRE); + break; + case CHANNEL_CARBON_MONOXIDE: + state = getQuantityTypeState(forecastData.measurements.carbonMonoxide, + Units.MICROGRAM_PER_CUBICMETRE); + break; + case CHANNEL_NITROGEN_MONOXIDE: + state = getQuantityTypeState(forecastData.measurements.nitrogenMonoxide, + Units.MICROGRAM_PER_CUBICMETRE); + break; + case CHANNEL_NITROGEN_DIOXIDE: + state = getQuantityTypeState(forecastData.measurements.nitrogenDioxide, + Units.MICROGRAM_PER_CUBICMETRE); + break; + case CHANNEL_OZONE: + state = getQuantityTypeState(forecastData.measurements.ozone, Units.MICROGRAM_PER_CUBICMETRE); + break; + case CHANNEL_SULPHUR_DIOXIDE: + state = getQuantityTypeState(forecastData.measurements.sulphurDioxide, + Units.MICROGRAM_PER_CUBICMETRE); + break; + case CHANNEL_AMMONIA: + state = getQuantityTypeState(forecastData.measurements.ammonia, Units.MICROGRAM_PER_CUBICMETRE); + break; + } + logger.debug("Update channel '{}' of group '{}' with new state '{}'.", channelId, channelGroupId, state); + updateState(channelUID, state); + } else { + logger.debug("No air pollution data available to update channel '{}' of group '{}'.", channelId, + channelGroupId); + } + } +} diff --git a/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/handler/OpenWeatherMapWeatherAndForecastHandler.java b/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/handler/OpenWeatherMapWeatherAndForecastHandler.java index b45e838672f..f0faccec36c 100644 --- a/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/handler/OpenWeatherMapWeatherAndForecastHandler.java +++ b/bundles/org.openhab.binding.openweathermap/src/main/java/org/openhab/binding/openweathermap/internal/handler/OpenWeatherMapWeatherAndForecastHandler.java @@ -428,6 +428,12 @@ public class OpenWeatherMapWeatherAndForecastHandler extends AbstractOpenWeather 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()); @@ -487,6 +493,10 @@ public class OpenWeatherMapWeatherAndForecastHandler extends AbstractOpenWeather Double snow = forecastData.getSnow(); state = getQuantityTypeState(snow == null ? 0 : snow, MILLI(METRE)); break; + case CHANNEL_PRECIP_PROBABILITY: + Double probability = forecastData.getPop(); + state = getQuantityTypeState(probability == null ? 0 : probability * 100.0, PERCENT); + break; } logger.debug("Update channel '{}' of group '{}' with new state '{}'.", channelId, channelGroupId, state); updateState(channelUID, state); diff --git a/bundles/org.openhab.binding.openweathermap/src/main/resources/OH-INF/config/config.xml b/bundles/org.openhab.binding.openweathermap/src/main/resources/OH-INF/config/config.xml index 5bdcaeb4030..002c9c0fa67 100644 --- a/bundles/org.openhab.binding.openweathermap/src/main/resources/OH-INF/config/config.xml +++ b/bundles/org.openhab.binding.openweathermap/src/main/resources/OH-INF/config/config.xml @@ -101,6 +101,19 @@ + + + location + + Location of weather in geographical coordinates (latitude/longitude/altitude). + + + + Number of hours for air pollution forecast. + 0 + + + location diff --git a/bundles/org.openhab.binding.openweathermap/src/main/resources/OH-INF/i18n/openweathermap_de.properties b/bundles/org.openhab.binding.openweathermap/src/main/resources/OH-INF/i18n/openweathermap_de.properties index 524d7457cc7..327534734d8 100644 --- a/bundles/org.openhab.binding.openweathermap/src/main/resources/OH-INF/i18n/openweathermap_de.properties +++ b/bundles/org.openhab.binding.openweathermap/src/main/resources/OH-INF/i18n/openweathermap_de.properties @@ -69,6 +69,9 @@ thing-type.openweathermap.weather-and-forecast.description = Erm thing-type.openweathermap.uvindex.label = UV-Index thing-type.openweathermap.uvindex.description = Ermöglicht die Anzeige des aktuellen UV-Index. +thing-type.openweathermap.air-pollution.label = Luftqualität +thing-type.openweathermap.air-pollution.description = Ermöglicht die Anzeige der aktuellen Luftqualität. + # thing types config thing-type.config.openweathermap.weather-and-forecast.location.label = Ort der Wetterdaten thing-type.config.openweathermap.weather-and-forecast.location.description = Ort der Wetterdaten in geographischen Koordinaten (Breitengrad/Längengrad/Höhe). @@ -85,6 +88,12 @@ thing-type.config.openweathermap.uvindex.location.description = Ort der Wetterda thing-type.config.openweathermap.uvindex.forecastDays.label = Tage thing-type.config.openweathermap.uvindex.forecastDays.description = Anzahl der Tage für die UV-Index Vorhersage. +thing-type.config.openweathermap.air-pollution.location.label = Ort der Wetterdaten +thing-type.config.openweathermap.air-pollution.location.description = Ort der Wetterdaten in geographischen Koordinaten (Breitengrad/Längengrad/Höhe). + +thing-type.config.openweathermap.air-pollution.forecastHours.label = Stunden +thing-type.config.openweathermap.air-pollution.forecastHours.description = Anzahl der Stunden für die Vorhersage der Luftqualität. + # channel group types channel-group-type.openweathermap.station.label = Wetterstation channel-group-type.openweathermap.station.description = Fasst Daten über die Wetterstation oder den Ort zusammen. @@ -104,6 +113,12 @@ channel-group-type.openweathermap.uvindex.description = Fasst aktuelle UV-Index channel-group-type.openweathermap.uvindexForecast.label = UV-Index Vorhersage channel-group-type.openweathermap.uvindexForecast.description = Fasst Daten der UV-Index Vorhersage zusammen. +channel-group-type.openweathermap.airPollution.label = Aktuelle Luftqualität +channel-group-type.openweathermap.airPollution.description = Fasst Daten über die aktuelle Luftqualität zusammen. + +channel-group-type.openweathermap.airPollutionForecast.label = Vorhersage der Luftqualität +channel-group-type.openweathermap.airPollutionForecast.description = Fasst Daten über die vorhergesagte Luftqualität zusammen. + # channel groups thing-type.openweathermap.weather-and-forecast.group.forecastHours03.label = Wettervorhersage für 3 Stunden thing-type.openweathermap.weather-and-forecast.group.forecastHours03.description = Fasst Daten der Wettervorhersage in den nächsten drei Stunden zusammen. @@ -184,6 +199,14 @@ channel-type.openweathermap.daily-forecast-time-stamp.label = Vorhersage Datum channel-type.openweathermap.daily-forecast-time-stamp.description = Zeigt das Datum der Vorhersage an. channel-type.openweathermap.daily-forecast-time-stamp.state.pattern = %1$td.%1$tm.%1$tY +channel-type.openweathermap.sunrise.label = Sonnenaufgang +channel-type.openweathermap.sunrise.description = Zeigt den Zeitpunkt des Sonnenaufgangs an. +channel-type.openweathermap.sunrise.state.pattern = %1$td.%1$tm.%1$tY %1$tH:%1$tM:%1$tS + +channel-type.openweathermap.sunset.label = Sonnenuntergang +channel-type.openweathermap.sunset.description = Zeigt den Zeitpunkt des Sonnenuntergangs an. +channel-type.openweathermap.sunset.state.pattern = %1$td.%1$tm.%1$tY %1$tH:%1$tM:%1$tS + channel-type.openweathermap.condition.label = Wetterlage channel-type.openweathermap.condition.description = Zeigt die aktuelle Wetterlage an. @@ -253,12 +276,79 @@ channel-type.openweathermap.snow.description = Zeigt den kumulierten Schnee der channel-type.openweathermap.forecasted-snow.label = Vorhergesagter Schnee channel-type.openweathermap.forecasted-snow.description = Zeigt die vorhergesagte Schneemenge an. +channel-type.openweathermap.precip-probability.label = Vorhergesagte Niederschlagswahrscheinlichkeit +channel-type.openweathermap.precip-probability.description = Zeigt die vorhergesagte Niederschlagswahrscheinlichkeit an. + channel-type.openweathermap.uvindex.label = UV-Index channel-type.openweathermap.uvindex.description = Zeigt den aktuellen UV-Index an. channel-type.openweathermap.forecasted-uvindex.label = Vorhergesagter UV-Index channel-type.openweathermap.forecasted-uvindex.description = Zeigt den vorhergesagten UV-Index an. +channel-type.openweathermap.air-quality-index.label = Luftqualitätsindex +channel-type.openweathermap.air-quality-index.description = Zeigt den aktuellen Luftqualitätsindex an. +channel-type.openweathermap.air-quality-index.state.option.1 = Gut +channel-type.openweathermap.air-quality-index.state.option.2 = Befriedigend +channel-type.openweathermap.air-quality-index.state.option.3 = Moderat +channel-type.openweathermap.air-quality-index.state.option.4 = Ungesund +channel-type.openweathermap.air-quality-index.state.option.5 = Äußerst Ungesund + +channel-type.openweathermap.forecasted-air-quality-index.label = Vorhergesagter Luftqualitätsindex +channel-type.openweathermap.forecasted-air-quality-index.description = Zeigt den vorhergesagten Luftqualitätsindex an. +channel-type.openweathermap.forecasted-air-quality-index.state.option.1 = Gut +channel-type.openweathermap.forecasted-air-quality-index.state.option.2 = Befriedigend +channel-type.openweathermap.forecasted-air-quality-index.state.option.3 = Moderat +channel-type.openweathermap.forecasted-air-quality-index.state.option.4 = Ungesund +channel-type.openweathermap.forecasted-air-quality-index.state.option.5 = Äußerst Ungesund + +channel-type.openweathermap.particulate-matter-2dot5.label = Feinstaub - PM2.5 +channel-type.openweathermap.particulate-matter-2dot5.description = Aktuelle Dichte von Teilchen mit Partikelgröße unter 2,5 µm. + +channel-type.openweathermap.forecasted-particulate-matter-2dot5.label = Vorhergesagter Feinstaub - PM2.5 +channel-type.openweathermap.forecasted-particulate-matter-2dot5.description = Vorhergesagte Dichte von Teilchen mit Partikelgröße unter 2,5 µm. + +channel-type.openweathermap.particulate-matter-10.label = Feinstaub - PM10 +channel-type.openweathermap.particulate-matter-10.description = Aktuelle Dichte von Teilchen mit Partikelgröße unter 10 µm. + +channel-type.openweathermap.forecasted-particulate-matter-10.label = Vorhergesagter Feinstaub - PM10 +channel-type.openweathermap.forecasted-particulate-matter-10.description = Vorhergesagte Dichte von Teilchen mit Partikelgröße unter 10 µm. + +channel-type.openweathermap.carbon-monoxide.label = Kohlenmonoxid +channel-type.openweathermap.carbon-monoxide.description = Aktuelle Konzentration an Kohlenmonoxid. + +channel-type.openweathermap.forecasted-carbon-monoxide.label = Vorhergesagter Kohlenmonoxid +channel-type.openweathermap.forecasted-carbon-monoxide.description = Vorhergesagte Konzentration an Kohlenmonoxid. + +channel-type.openweathermap.nitrogen-monoxide.label = Stickstoffmonoxid +channel-type.openweathermap.nitrogen-monoxide.description = Aktuelle Konzentration an Stickstoffmonoxid. + +channel-type.openweathermap.forecasted-nitrogen-monoxide.label = Vorhergesagter Stickstoffmonoxid +channel-type.openweathermap.forecasted-nitrogen-monoxide.description = Vorhergesagte Konzentration an Stickstoffmonoxid. + +channel-type.openweathermap.nitrogen-dioxide.label = Stickstoffdioxid +channel-type.openweathermap.nitrogen-dioxide.description = Aktuelle Konzentration an Stickstoffdioxid. + +channel-type.openweathermap.forecasted-nitrogen-dioxide.label = Vorhergesagter Stickstoffdioxid +channel-type.openweathermap.forecasted-nitrogen-dioxide.description = Vorhergesagte Konzentration an Stickstoffdioxid. + +channel-type.openweathermap.ozone.label = Ozon +channel-type.openweathermap.ozone.description = Aktuelle Konzentration an Ozon. + +channel-type.openweathermap.forecasted-ozone.label = Vorhergesagter Ozon +channel-type.openweathermap.forecasted-ozone.description = Vorhergesagte Konzentration an Ozon. + +channel-type.openweathermap.sulphur-dioxide.label = Schwefeldioxid +channel-type.openweathermap.sulphur-dioxide.description = Aktuelle Konzentration an Schwefeldioxid. + +channel-type.openweathermap.forecasted-sulphur-dioxide.label = Vorhergesagter Schwefeldioxid +channel-type.openweathermap.forecasted-sulphur-dioxide.description = Vorhergesagte Konzentration an Schwefeldioxid. + +channel-type.openweathermap.ammonia.label = Ammoniak +channel-type.openweathermap.ammonia.description = Aktuelle Konzentration an Ammoniak. + +channel-type.openweathermap.forecasted-ammonia.label = Vorhergesagter Ammoniak +channel-type.openweathermap.forecasted-ammonia.description = Vorhergesagte Konzentration an Ammoniak. + # thing status offline.conf-error-missing-apikey = Der Parameter 'API Schlüssel' muss konfiguriert werden. offline.conf-error-invalid-apikey = Ungültiger 'API Schlüssel'. Mehr Infos unter https://openweathermap.org/faq#error401. @@ -270,6 +360,7 @@ offline.conf-error-parsing-location = Der Parameter 'Ort' kann nicht in Latitude offline.conf-error-not-supported-number-of-hours = Der Parameter 'forecastHours' muss zwischen 0 und 120 liegen - Schrittweite: 3. offline.conf-error-not-supported-number-of-days = Der Parameter 'forecastDays' muss zwischen 0 und 16 liegen. offline.conf-error-not-supported-uvindex-number-of-days = Der Parameter 'forecastDays' muss zwischen 1 und 8 liegen. +offline.conf-error-not-supported-air-pollution-number-of-hours = Der Parameter 'forecastHours' muss zwischen 0 und 120 liegen - Schrittweite: 1. 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. @@ -278,3 +369,4 @@ offline.conf-error-not-supported-onecall-number-of-days = Der Parameter 'forecas # discovery result discovery.openweathermap.weather-and-forecast.api.local.label = Lokales Wetter und Wettervorhersage discovery.openweathermap.uvindex.api.local.label = Lokaler UV-Index +discovery.openweathermap.air-pollution.api.local.label = Lokale Luftqualität diff --git a/bundles/org.openhab.binding.openweathermap/src/main/resources/OH-INF/thing/channel-types.xml b/bundles/org.openhab.binding.openweathermap/src/main/resources/OH-INF/thing/channel-types.xml index 9bbf626368e..9a7a4d39a6b 100644 --- a/bundles/org.openhab.binding.openweathermap/src/main/resources/OH-INF/thing/channel-types.xml +++ b/bundles/org.openhab.binding.openweathermap/src/main/resources/OH-INF/thing/channel-types.xml @@ -84,6 +84,9 @@ + + + @@ -105,6 +108,40 @@ + + + This is the current air pollution. + + + + + + + + + + + + + + + + + This is the forecasted air pollution. + + + + + + + + + + + + + + Current weather data from the One Call API. @@ -576,6 +613,148 @@ + + Number + + Current air quality index. + + + + + + + + + + + + + Number + + Forecasted air quality index. + + + + + + + + + + + + + Number:Density + + Current density of particles less than 2.5 µm in diameter. + + + + + Number:Density + + Forecasted density of particles less than 2.5 µm in diameter. + + + + + Number:Density + + Current density of particles less than 10 µm in diameter. + + + + + Number:Density + + Forecasted density of particles less than 10 µm in diameter. + + + + + Number:Density + + Current concentration of carbon monoxide. + + + + + Number:Density + + Forecasted concentration of carbon monoxide. + + + + + Number:Density + + Current concentration of nitrogen monoxide. + + + + + Number:Density + + Forecasted concentration of nitrogen monoxide. + + + + + Number:Density + + Current concentration of nitrogen dioxide. + + + + + Number:Density + + Forecasted concentration of nitrogen dioxide. + + + + + Number:Density + + Current concentration of ozone. + + + + + Number:Density + + Forecasted concentration of ozone. + + + + + Number:Density + + Current concentration of sulphur dioxide. + + + + + Number:Density + + Forecasted concentration of sulphur dioxide. + + + + + Number:Density + + Current concentration of ammonia. + + + + + Number:Density + + Forecasted concentration of ammonia. + + + Number:Length @@ -585,9 +764,9 @@ Number:Dimensionless - + Forecasted precipitation probability. + Rain - diff --git a/bundles/org.openhab.binding.openweathermap/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.openweathermap/src/main/resources/OH-INF/thing/thing-types.xml index 848132a6865..2155ea55ba4 100644 --- a/bundles/org.openhab.binding.openweathermap/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.openweathermap/src/main/resources/OH-INF/thing/thing-types.xml @@ -116,6 +116,23 @@ + + + + + + + Provides air pollution data from the OpenWeatherMap API. + + + + + + location + + + +