[openweathermap] Added support for Air Pollution API (#10343)

Signed-off-by: Christoph Weitkamp <github@christophweitkamp.de>
This commit is contained in:
Christoph Weitkamp 2021-03-27 20:04:02 +01:00 committed by GitHub
parent 1fa1f54272
commit b1e48e0db9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 866 additions and 23 deletions

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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<String, String> 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");

View File

@ -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))

View File

@ -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<org.openhab.binding.openweathermap.internal.dto.airpollution.List> list;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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)) {

View File

@ -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<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()));
public static final Set<ThingTypeUID> 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;

View File

@ -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<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_WEATHER_API);
public static final Set<ThingTypeUID> 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 {

View File

@ -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<Channel> toBeAddedChannels = new ArrayList<>();
List<Channel> 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);
}
}
}

View File

@ -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);

View File

@ -101,6 +101,19 @@
</parameter>
</config-description>
<config-description uri="thing-type:openweathermap:air-pollution">
<parameter name="location" type="text" required="true">
<context>location</context>
<label>Location of Weather</label>
<description>Location of weather in geographical coordinates (latitude/longitude/altitude).</description>
</parameter>
<parameter name="forecastHours" type="integer" min="0" max="120" step="1">
<label>Number of Hours</label>
<description>Number of hours for air pollution forecast.</description>
<default>0</default>
</parameter>
</config-description>
<config-description uri="thing-type:openweathermap:onecall">
<parameter name="location" type="text" required="true">
<context>location</context>

View File

@ -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

View File

@ -84,6 +84,9 @@
<channel id="cloudiness" typeId="forecasted-cloudiness"/>
<channel id="rain" typeId="forecasted-rain"/>
<channel id="snow" typeId="forecasted-snow"/>
<channel id="precip-probability" typeId="precip-probability"/>
<channel id="sunrise" typeId="sunrise"/>
<channel id="sunset" typeId="sunset"/>
</channels>
</channel-group-type>
@ -105,6 +108,40 @@
</channels>
</channel-group-type>
<channel-group-type id="airPollution">
<label>Current Air Pollution</label>
<description>This is the current air pollution.</description>
<channels>
<channel id="time-stamp" typeId="time-stamp"/>
<channel id="airQualityIndex" typeId="air-quality-index"/>
<channel id="particulateMatter2dot5" typeId="particulate-matter-2dot5"/>
<channel id="particulateMatter10" typeId="particulate-matter-10"/>
<channel id="carbonMonoxide" typeId="carbon-monoxide"/>
<channel id="nitrogenMonoxide" typeId="nitrogen-monoxide"/>
<channel id="nitrogenDioxide" typeId="nitrogen-dioxide"/>
<channel id="ozone" typeId="ozone"/>
<channel id="sulphurDioxide" typeId="sulphur-dioxide"/>
<channel id="ammonia" typeId="ammonia"/>
</channels>
</channel-group-type>
<channel-group-type id="airPollutionForecast">
<label>Forecasted Air Pollution</label>
<description>This is the forecasted air pollution.</description>
<channels>
<channel id="time-stamp" typeId="hourly-forecast-time-stamp"/>
<channel id="airQualityIndex" typeId="forecasted-air-quality-index"/>
<channel id="particulateMatter2dot5" typeId="forecasted-particulate-matter-2dot5"/>
<channel id="particulateMatter10" typeId="forecasted-particulate-matter-10"/>
<channel id="carbonMonoxide" typeId="forecasted-carbon-monoxide"/>
<channel id="nitrogenMonoxide" typeId="forecasted-nitrogen-monoxide"/>
<channel id="nitrogenDioxide" typeId="forecasted-nitrogen-dioxide"/>
<channel id="ozone" typeId="forecasted-ozone"/>
<channel id="sulphurDioxide" typeId="forecasted-sulphur-dioxide"/>
<channel id="ammonia" typeId="forecasted-ammonia"/>
</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>
@ -576,6 +613,148 @@
<state readOnly="true" pattern="%.1f"/>
</channel-type>
<channel-type id="air-quality-index">
<item-type>Number</item-type>
<label>Air Quality Index</label>
<description>Current air quality index.</description>
<state readOnly="true" pattern="%.0f">
<options>
<option value="1">Good</option>
<option value="2">Fair</option>
<option value="3">Moderate</option>
<option value="4">Poor</option>
<option value="5">Very Poor</option>
</options>
</state>
</channel-type>
<channel-type id="forecasted-air-quality-index">
<item-type>Number</item-type>
<label>Forecasted Air Quality Index</label>
<description>Forecasted air quality index.</description>
<state readOnly="true" pattern="%.0f">
<options>
<option value="1">Good</option>
<option value="2">Fair</option>
<option value="3">Moderate</option>
<option value="4">Poor</option>
<option value="5">Very Poor</option>
</options>
</state>
</channel-type>
<channel-type id="particulate-matter-2dot5">
<item-type>Number:Density</item-type>
<label>Particulate Matter - PM2.5</label>
<description>Current density of particles less than 2.5 µm in diameter.</description>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="forecasted-particulate-matter-2dot5">
<item-type>Number:Density</item-type>
<label>Forecasted Particulate Matter - PM2.5</label>
<description>Forecasted density of particles less than 2.5 µm in diameter.</description>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="forecasted-particulate-matter-10">
<item-type>Number:Density</item-type>
<label>Particulate Matter - PM10</label>
<description>Current density of particles less than 10 µm in diameter.</description>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="particulate-matter-10">
<item-type>Number:Density</item-type>
<label>Forecasted Particulate Matter - PM10</label>
<description>Forecasted density of particles less than 10 µm in diameter.</description>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="carbon-monoxide">
<item-type>Number:Density</item-type>
<label>Carbon Monoxide</label>
<description>Current concentration of carbon monoxide.</description>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>
<channel-type id="forecasted-carbon-monoxide">
<item-type>Number:Density</item-type>
<label>Forecasted Carbon Monoxide</label>
<description>Forecasted concentration of carbon monoxide.</description>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>
<channel-type id="nitrogen-monoxide">
<item-type>Number:Density</item-type>
<label>Nitrogen Monoxide</label>
<description>Current concentration of nitrogen monoxide.</description>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>
<channel-type id="forecasted-nitrogen-monoxide">
<item-type>Number:Density</item-type>
<label>Forecasted Nitrogen Monoxide</label>
<description>Forecasted concentration of nitrogen monoxide.</description>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>
<channel-type id="nitrogen-dioxide">
<item-type>Number:Density</item-type>
<label>Nitrogen Dioxide</label>
<description>Current concentration of nitrogen dioxide.</description>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>
<channel-type id="forecasted-nitrogen-dioxide">
<item-type>Number:Density</item-type>
<label>Forecasted Nitrogen Dioxide</label>
<description>Forecasted concentration of nitrogen dioxide.</description>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>
<channel-type id="ozone">
<item-type>Number:Density</item-type>
<label>Ozone</label>
<description>Current concentration of ozone.</description>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>
<channel-type id="forecasted-ozone">
<item-type>Number:Density</item-type>
<label>Forecasted Ozone</label>
<description>Forecasted concentration of ozone.</description>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>
<channel-type id="sulphur-dioxide">
<item-type>Number:Density</item-type>
<label>Sulphur Dioxide</label>
<description>Current concentration of sulphur dioxide.</description>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>
<channel-type id="forecasted-sulphur-dioxide">
<item-type>Number:Density</item-type>
<label>Forecasted Sulphur Dioxide</label>
<description>Forecasted concentration of sulphur dioxide.</description>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>
<channel-type id="ammonia">
<item-type>Number:Density</item-type>
<label>Ammonia</label>
<description>Current concentration of ammonia.</description>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>
<channel-type id="forecasted-ammonia">
<item-type>Number:Density</item-type>
<label>Forecasted Ammonia</label>
<description>Forecasted concentration of ammonia.</description>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>
<channel-type id="visibility">
<item-type>Number:Length</item-type>
<label>Visibility</label>
@ -585,9 +764,9 @@
<channel-type id="precip-probability">
<item-type>Number:Dimensionless</item-type>
<label>Probability</label>
<label>Precipitation Probability</label>
<description>Forecasted precipitation probability.</description>
<category>Rain</category>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>
</thing:thing-descriptions>

View File

@ -116,6 +116,23 @@
<config-description-ref uri="thing-type:openweathermap:uvindex"/>
</thing-type>
<thing-type id="air-pollution">
<supported-bridge-type-refs>
<bridge-type-ref id="weather-api"/>
</supported-bridge-type-refs>
<label>Air Pollution</label>
<description>Provides air pollution data from the OpenWeatherMap API.</description>
<channel-groups>
<channel-group id="current" typeId="airPollution"/>
</channel-groups>
<representation-property>location</representation-property>
<config-description-ref uri="thing-type:openweathermap:air-pollution"/>
</thing-type>
<thing-type id="onecall">
<supported-bridge-type-refs>
<bridge-type-ref id="weather-api"/>