[openweathermap] Add support for persisting OneCall API forecasts (#15963)

Implement time series support introduced by https://github.com/openhab/openhab-core/pull/3597.

Signed-off-by: Florian Hotze <florianh_dev@icloud.com>
This commit is contained in:
Florian Hotze 2023-12-14 20:21:54 +01:00 committed by GitHub
parent ea3e608c81
commit c81a263b91
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 655 additions and 276 deletions

View File

@ -50,6 +50,7 @@ New Subscribers to the One Call API will require setting the API version to 3.0
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.
It requires coordinates of the location of your interest.
You can add as many `onecall` things for different locations to your setup as you like to observe.
It also supports persisting forecast data using time series support, please read [Persisting Time Series](#persisting-time-series).
### One Call API History Data
@ -104,13 +105,16 @@ Once the parameter `forecastHours` will be changed, the available channel groups
### One Call API Weather and Forecast
| Parameter | Description |
|----------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|-----------------|---------------------------------------------------------------------------------------------------------------------------------------|
| location | Location of weather in geographical coordinates (latitude/longitude/altitude). **Mandatory** |
| forecastMinutes| Number of minutes for minutely precipitation forecast. Optional, the default value is 0, so by default **no** minutely forecast data is fetched. (min="0", max="60"). |
| forecastHours | Number of hours for hourly forecast. Optional, the default value is 24 (min="0", max="48"). |
| forecastDays | Number of days for daily forecast (including todays forecast). Optional, the default value is 6 (min="0", max="8"). |
| forecastMinutes | Number of minutes for minutely precipitation forecast as minutely channels. Optional, the default value is 0 (min="0", max="60"). |
| forecastHours | Number of hours for hourly forecast as hourly channels. Optional, the default value is 12 (min="0", max="48"). |
| forecastDays | Number of days for daily forecast (including todays forecast) as daily channels. Optional, the default value is 6 (min="0", max="8"). |
| numberOfAlerts | Number of alerts to be shown. Optional, the default value is 0 (min="0", max="5"). |
Set `forecastMinutes`, `forecastHours` and `forecastDays` to `0` if you only want to use the channels with time series support.
In a future release, this will become the default setting as usage of the time series channels instead is encouraged.
### One Call API History Data
| Parameter | Description |
@ -128,7 +132,7 @@ Once the parameter `forecastHours` will be changed, the available channel groups
| station | name | String | Name of the weather station or the city. |
| station | location | Location | Location of the weather station or the city. |
These channels are not supported in the One Call API
These channels are not supported in the One Call API.
### Current Weather
@ -166,9 +170,11 @@ The "3h" value will be divided by three to always have an estimated value for on
Where available, the One Call API provides a minutely precipitation forecast for the next 60 minutes.
| Channel Group ID | Channel ID | Item Type | Description |
|--------------------------------------------------------|----------------------|----------------------|----------------------------------------------------------------------------|
|-----------------------------------------------------------|---------------|---------------|-----------------------------------------------------------------|
| forecastMinutes01 ... forecastMinutes60 | time-stamp | DateTime | Time of data forecasted. |
| forecastMinutes01 ... forecastMinutes60 | precipitation | Number:Length | Expected precipitation volume. |
| forecastMinutely, forecastMinutes01 ... forecastMinutes60 | precipitation | Number:Length | Expected precipitation volume. |
The `forecastMinutely` channel group provides [time series support](#persisting-time-series).
### 3 Hour Forecast
@ -197,42 +203,49 @@ Where available, the One Call API provides a minutely precipitation forecast for
### One Call API Hourly Forecast
The One Call API provides hourly forecasts for 48 hours.
The Channel Group IDs for those are `forecastHours01` to `forecastHours48`.
The Channel Group IDs for those are `forecastHours01` to `forecastHours48`, and `forecastHourly` for channels with time series support.
See above for a description of the available channels.
The `forecastHourly` channel group provides all channels as described above with [time series support](#persisting-time-series), except `time-stamp`.
In a future release, the `forecastHours01` to `forecastHours48` channel groups won't be created anymore by default as usage of the time series channels instead is encouraged.
### Daily Forecast
| 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. |
| forecastToday, forecastTomorrow, forecastDay2, ... forecastDay16 | icon-id | String | Id of the icon representing the forecasted weather condition. **Advanced** |
| forecastToday, forecastTomorrow, forecastDay2, ... forecastDay16 | apparent-temperature | Number:Temperature | Forecasted apparent temperature. Not available in the One Call API |
| forecastToday, forecastTomorrow, forecastDay2, ... forecastDay16 | min-temperature | Number:Temperature | Minimum forecasted temperature of a day. |
| forecastToday, forecastTomorrow, forecastDay2, ... forecastDay16 | max-temperature | Number:Temperature | Maximum forecasted temperature of a day. |
| forecastToday, forecastTomorrow, forecastDay2, ... forecastDay16 | pressure | Number:Pressure | Forecasted barometric pressure. |
| forecastToday, forecastTomorrow, forecastDay2, ... forecastDay16 | humidity | Number:Dimensionless | Forecasted atmospheric humidity. |
| forecastToday, forecastTomorrow, forecastDay2, ... forecastDay16 | wind-speed | Number:Speed | Forecasted wind speed. |
| forecastToday, forecastTomorrow, forecastDay2, ... forecastDay16 | wind-direction | Number:Angle | Forecasted wind direction. |
| forecastToday, forecastTomorrow, forecastDay2, ... forecastDay16 | gust-speed | Number:Speed | Forecasted gust speed. **Advanced** |
| forecastToday, forecastTomorrow, forecastDay2, ... forecastDay16 | cloudiness | Number:Dimensionless | Forecasted cloudiness. |
| forecastToday, forecastTomorrow, forecastDay2, ... forecastDay16 | rain | Number:Length | Expected rain volume of a day. |
| 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 |
| forecastToday, forecastTomorrow, forecastDay2, ... forecastDay7 | night-temperature | Number:Temperature | Expected night-temperature. Only available in the One Call API |
| forecastToday, forecastTomorrow, forecastDay2, ... forecastDay7 | apparent-morning | Number:Temperature | Expected apparent temperature in the morning. Only available in the One Call API |
| forecastToday, forecastTomorrow, forecastDay2, ... forecastDay7 | apparent-day | Number:Temperature | Expected apparent temperature in the day. Only available in the One Call API |
| forecastToday, forecastTomorrow, forecastDay2, ... forecastDay7 | apparent-evening | Number:Temperature | Expected apparent temperature in the evening. Only available in the One Call API |
| forecastToday, forecastTomorrow, forecastDay2, ... forecastDay7 | apparent-night | Number:Temperature | Expected apparent temperature in the night. Only available in the One Call API |
| forecastDaily, forecastToday, forecastTomorrow, forecastDay2, ... forecastDay16 | sunrise | DateTime | Time of sunrise for the given day. |
| forecastDaily, forecastToday, forecastTomorrow, forecastDay2, ... forecastDay16 | sunset | DateTime | Time of sunset for the given day. |
| forecastDaily, forecastToday, forecastTomorrow, forecastDay2, ... forecastDay16 | condition | String | Forecast weather condition. |
| forecastDaily, forecastToday, forecastTomorrow, forecastDay2, ... forecastDay16 | condition-id | String | Id of the forecasted weather condition. **Advanced** |
| forecastDaily, forecastToday, forecastTomorrow, forecastDay2, ... forecastDay16 | icon | Image | Icon representing the forecasted weather condition. |
| forecastDaily, forecastToday, forecastTomorrow, forecastDay2, ... forecastDay16 | icon-id | String | Id of the icon representing the forecasted weather condition. **Advanced** |
| forecastDaily, forecastToday, forecastTomorrow, forecastDay2, ... forecastDay16 | apparent-temperature | Number:Temperature | Forecasted apparent temperature. Not available in the One Call API |
| forecastDaily, forecastToday, forecastTomorrow, forecastDay2, ... forecastDay16 | min-temperature | Number:Temperature | Minimum forecasted temperature of a day. |
| forecastDaily, forecastToday, forecastTomorrow, forecastDay2, ... forecastDay16 | max-temperature | Number:Temperature | Maximum forecasted temperature of a day. |
| forecastDaily, forecastToday, forecastTomorrow, forecastDay2, ... forecastDay16 | pressure | Number:Pressure | Forecasted barometric pressure. |
| forecastDaily, forecastToday, forecastTomorrow, forecastDay2, ... forecastDay16 | humidity | Number:Dimensionless | Forecasted atmospheric humidity. |
| forecastDaily, forecastToday, forecastTomorrow, forecastDay2, ... forecastDay16 | wind-speed | Number:Speed | Forecasted wind speed. |
| forecastDaily, forecastToday, forecastTomorrow, forecastDay2, ... forecastDay16 | wind-direction | Number:Angle | Forecasted wind direction. |
| forecastDaily, forecastToday, forecastTomorrow, forecastDay2, ... forecastDay16 | gust-speed | Number:Speed | Forecasted gust speed. **Advanced** |
| forecastDaily, forecastToday, forecastTomorrow, forecastDay2, ... forecastDay16 | cloudiness | Number:Dimensionless | Forecasted cloudiness. |
| forecastDaily, forecastToday, forecastTomorrow, forecastDay2, ... forecastDay16 | rain | Number:Length | Expected rain volume of a day. |
| forecastDaily, forecastToday, forecastTomorrow, forecastDay2, ... forecastDay16 | snow | Number:Length | Expected snow volume of a day. |
| forecastDaily, forecastToday, forecastTomorrow, forecastDay2, ... forecastDay7 | dew-point | Number:Temperature | Expected dew-point. Only available in the One Call API |
| forecastDaily, forecastToday, forecastTomorrow, forecastDay2, ... forecastDay7 | uvindex | Number | Forecasted Midday UV Index. Only available in the One Call API |
| forecastDaily, forecastToday, forecastTomorrow, forecastDay2, ... forecastDay7 | precip-probability | Number:Dimensionless | Precipitation probability. |
| forecastDaily, forecastToday, forecastTomorrow, forecastDay2, ... forecastDay7 | morning-temperature | Number:Temperature | Expected morning temperature. Only available in the One Call API |
| forecastDaily, forecastToday, forecastTomorrow, forecastDay2, ... forecastDay7 | day-temperature | Number:Temperature | Expected day-temperature. Only available in the One Call API |
| forecastDaily, forecastToday, forecastTomorrow, forecastDay2, ... forecastDay7 | evening-temperature | Number:Temperature | Expected evening-temperature. Only available in the One Call API |
| forecastDaily, forecastToday, forecastTomorrow, forecastDay2, ... forecastDay7 | night-temperature | Number:Temperature | Expected night-temperature. Only available in the One Call API |
| forecastDaily, forecastToday, forecastTomorrow, forecastDay2, ... forecastDay7 | apparent-morning | Number:Temperature | Expected apparent temperature in the morning. Only available in the One Call API |
| forecastDaily, forecastToday, forecastTomorrow, forecastDay2, ... forecastDay7 | apparent-day | Number:Temperature | Expected apparent temperature in the day. Only available in the One Call API |
| forecastDaily, forecastToday, forecastTomorrow, forecastDay2, ... forecastDay7 | apparent-evening | Number:Temperature | Expected apparent temperature in the evening. Only available in the One Call API |
| forecastDaily, forecastToday, forecastTomorrow, forecastDay2, ... forecastDay7 | apparent-night | Number:Temperature | Expected apparent temperature in the night. Only available in the One Call API |
The `forecastDaily` channel group provides [time series support](#persisting-time-series).
In a future release, the `forecastToday` to `forecastDay7` channel groups won't be created anymore by default as usage of the time series channels instead is encouraged.
### One Call API Weather Warnings
@ -268,6 +281,21 @@ The `uvindex` channel is also available in the current data and the daily foreca
| 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. |
## Persisting Time Series
The binding offers support for persisting forecast values for most channels of the [One Call API Weather and Forecast](#one-call-api-weather-and-forecast) Thing.
The recommended persistence strategy is `forecast`, as it ensures a clean history without redundancy.
### Configuration
Make sure you have a persistence service installed and ready for use.
To configure persisting forecast data, create and link Items to those channels with time series support (as usual).
Next, enable persistence for these Items using the `forecast` persistence strategy.
Finally, open the UI, search for one of the newly created Items, open the analyzer and select a future time range.
To access forecast data stored in persistence from scripts and rules, use the [Persistence Extensions]({{base}}/configuration/persistence.html#persistence-extensions-in-scripts-and-rules).
## Full Example
### Things

View File

@ -16,7 +16,9 @@ import static org.openhab.binding.openweathermap.internal.OpenWeatherMapBindingC
import static org.openhab.core.library.unit.MetricPrefix.*;
import static org.openhab.core.library.unit.SIUnits.*;
import static org.openhab.core.library.unit.Units.*;
import static org.openhab.core.types.TimeSeries.Policy.REPLACE;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
@ -30,6 +32,8 @@ import org.openhab.binding.openweathermap.internal.dto.OpenWeatherMapOneCallAPID
import org.openhab.binding.openweathermap.internal.dto.forecast.daily.FeelsLikeTemp;
import org.openhab.binding.openweathermap.internal.dto.forecast.daily.Temp;
import org.openhab.binding.openweathermap.internal.dto.onecall.Alert;
import org.openhab.binding.openweathermap.internal.dto.onecall.Daily;
import org.openhab.binding.openweathermap.internal.dto.onecall.Hourly;
import org.openhab.binding.openweathermap.internal.dto.onecall.Precipitation;
import org.openhab.core.i18n.CommunicationException;
import org.openhab.core.i18n.ConfigurationException;
@ -42,6 +46,7 @@ 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.TimeSeries;
import org.openhab.core.types.UnDefType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -54,6 +59,7 @@ import com.google.gson.JsonSyntaxException;
*
* @author Wolfgang Klimt - Initial contribution
* @author Christoph Weitkamp - Added weather alerts
* @author Florian Hotze - Added support for persisting forecasts
*/
@NonNullByDefault
public class OpenWeatherMapOneCallHandler extends AbstractOpenWeatherMapHandler {
@ -61,8 +67,11 @@ public class OpenWeatherMapOneCallHandler extends AbstractOpenWeatherMapHandler
private final Logger logger = LoggerFactory.getLogger(OpenWeatherMapOneCallHandler.class);
private static final String CHANNEL_GROUP_MINUTELY_FORECAST_PREFIX = "forecastMinutes";
private static final String CHANNEL_GROUP_MINUTELY_TIMESERIES_PREFIX = "forecastMinutely";
private static final String CHANNEL_GROUP_HOURLY_FORECAST_PREFIX = "forecastHours";
private static final String CHANNEL_GROUP_HOURLY_TIMESERIES_PREFIX = "forecastHourly";
private static final String CHANNEL_GROUP_DAILY_FORECAST_PREFIX = "forecastDay";
private static final String CHANNEL_GROUP_DAILY_TIMESERIES_PREFIX = "forecastDaily";
private static final String CHANNEL_GROUP_ALERTS_PREFIX = "alerts";
private static final Pattern CHANNEL_GROUP_HOURLY_FORECAST_PREFIX_PATTERN = Pattern
.compile(CHANNEL_GROUP_HOURLY_FORECAST_PREFIX + "([0-9]*)");
@ -75,9 +84,10 @@ public class OpenWeatherMapOneCallHandler extends AbstractOpenWeatherMapHandler
private @Nullable OpenWeatherMapOneCallAPIData weatherData;
private int forecastMinutes = 60;
private int forecastHours = 24;
private int forecastDays = 8;
// forecastMinutes, -Hours and -Days determine the number of channel groups to create for each type
private int forecastMinutes = 0;
private int forecastHours = 12;
private int forecastDays = 6;
private int numberOfAlerts = 0;
public OpenWeatherMapOneCallHandler(Thing thing, final TimeZoneProvider timeZoneProvider) {
@ -217,8 +227,8 @@ public class OpenWeatherMapOneCallHandler extends AbstractOpenWeatherMapHandler
throws CommunicationException, ConfigurationException {
logger.debug("Update weather and forecast data of thing '{}'.", getThing().getUID());
try {
weatherData = connection.getOneCallAPIData(location, forecastMinutes == 0, forecastHours == 0,
forecastDays == 0, numberOfAlerts == 0);
// Include minutely, hourly and daily data as this is needed for the time series channels
weatherData = connection.getOneCallAPIData(location, false, false, false, numberOfAlerts == 0);
return true;
} catch (JsonSyntaxException e) {
logger.debug("JsonSyntaxException occurred during execution: {}", e.getMessage(), e);
@ -240,6 +250,15 @@ public class OpenWeatherMapOneCallHandler extends AbstractOpenWeatherMapHandler
case CHANNEL_GROUP_ONECALL_TOMORROW:
updateDailyForecastChannel(channelUID, 1);
break;
case CHANNEL_GROUP_MINUTELY_TIMESERIES_PREFIX:
updateMinutelyForecastTimeSeries(channelUID);
break;
case CHANNEL_GROUP_HOURLY_TIMESERIES_PREFIX:
updateHourlyForecastTimeSeries(channelUID);
break;
case CHANNEL_GROUP_DAILY_TIMESERIES_PREFIX:
updateDailyForecastTimeSeries(channelUID);
break;
default:
int i;
Matcher hourlyForecastMatcher = CHANNEL_GROUP_HOURLY_FORECAST_PREFIX_PATTERN.matcher(channelGroupId);
@ -412,8 +431,41 @@ public class OpenWeatherMapOneCallHandler extends AbstractOpenWeatherMapHandler
}
}
private void updateMinutelyForecastTimeSeries(ChannelUID channelUID) {
String channelId = channelUID.getIdWithoutGroup();
String channelGroupId = channelUID.getGroupId();
OpenWeatherMapOneCallAPIData localWeatherData = weatherData;
if (channelId.equals(CHANNEL_TIME_STAMP)) {
logger.debug("Channel `{}` of group '{}' is no supported time-series channel.", channelId, channelGroupId);
return;
}
if (localWeatherData != null && !localWeatherData.getMinutely().isEmpty()) {
List<org.openhab.binding.openweathermap.internal.dto.onecall.Minutely> forecastData = localWeatherData
.getMinutely();
TimeSeries timeSeries = new TimeSeries(REPLACE);
forecastData.forEach((m) -> {
if (channelId.equals(CHANNEL_PRECIPITATION)) {
State state = UnDefType.UNDEF;
Instant timestamp = Instant.ofEpochSecond(m.getDt());
double precipitation = m.getPrecipitation();
state = getQuantityTypeState(precipitation, MILLI(METRE));
timeSeries.add(timestamp, state);
} else {
// This should not happen
logger.warn("Unknown channel id {} in onecall minutely weather data", channelId);
return;
}
});
logger.debug("Update channel '{}' of group '{}' with new time-series '{}'.", channelId, channelGroupId,
timeSeries);
sendTimeSeries(channelUID, timeSeries);
} else {
logger.debug("No weather data available to update channel '{}' of group '{}'.", channelId, channelGroupId);
}
}
/**
* Update the channel from the last OpenWeatherMap data retrieved.
* Update the hourly forecast channel from the last OpenWeatherMap data retrieved.
*
* @param channelUID the id identifying the channel to be updated
* @param count the index of the hourly data referenced by the channel (hour 1 is count 0)
@ -431,6 +483,46 @@ public class OpenWeatherMapOneCallHandler extends AbstractOpenWeatherMapHandler
if (localWeatherData != null && localWeatherData.getHourly().size() > count) {
org.openhab.binding.openweathermap.internal.dto.onecall.Hourly forecastData = localWeatherData.getHourly()
.get(count);
State state = getHourlyForecastState(channelId, forecastData, localWeatherData);
logger.debug("Update channel '{}' of group '{}' with new state '{}'.", channelId, channelGroupId, state);
updateState(channelUID, state);
} else {
logger.debug("No weather data available to update channel '{}' of group '{}'.", channelId, channelGroupId);
}
}
/**
* Update the hourly forecast time series channel from the last OpenWeatherMap data retrieved.
*
* @param channelUID the id identifying the channel to be updated
*/
private void updateHourlyForecastTimeSeries(ChannelUID channelUID) {
String channelId = channelUID.getIdWithoutGroup();
String channelGroupId = channelUID.getGroupId();
if (channelId.equals(CHANNEL_TIME_STAMP)) {
logger.debug("Channel `{}` of group '{}' is no supported time-series channel.", channelId, channelGroupId);
return;
}
OpenWeatherMapOneCallAPIData localWeatherData = weatherData;
if (localWeatherData != null && !localWeatherData.getHourly().isEmpty()) {
List<org.openhab.binding.openweathermap.internal.dto.onecall.Hourly> forecastData = localWeatherData
.getHourly();
TimeSeries timeSeries = new TimeSeries(REPLACE);
forecastData.forEach((h) -> {
Instant timestamp = Instant.ofEpochSecond(h.getDt());
State state = getHourlyForecastState(channelId, h, localWeatherData);
timeSeries.add(timestamp, state);
});
logger.debug("Update channel '{}' of group '{}' with new time-series '{}'.", channelId, channelGroupId,
timeSeries);
sendTimeSeries(channelUID, timeSeries);
} else {
logger.debug("No weather data available to update channel '{}'.", channelId);
}
}
private State getHourlyForecastState(String channelId, Hourly forecastData,
OpenWeatherMapOneCallAPIData localWeatherData) {
State state = UnDefType.UNDEF;
switch (channelId) {
case CHANNEL_TIME_STAMP:
@ -501,18 +593,14 @@ public class OpenWeatherMapOneCallHandler extends AbstractOpenWeatherMapHandler
break;
default:
// This should not happen
logger.warn("Unknown channel id {} in onecall hourly weather data", channelId);
logger.warn("Unknown channel id {} in OneCall hourly weather data", channelId);
break;
}
logger.debug("Update channel '{}' of group '{}' with new state '{}'.", channelId, channelGroupId, state);
updateState(channelUID, state);
} else {
logger.debug("No weather data available to update channel '{}' of group '{}'.", channelId, channelGroupId);
}
return state;
}
/**
* Update the channel from the last OpenWeatherMap data retrieved.
* Update the daily forecast channel from the last OpenWeatherMap data retrieved.
*
* @param channelUID the id identifying the channel to be updated
* @param count the index of the daily data referenced by the channel (today is count 0)
@ -530,9 +618,44 @@ public class OpenWeatherMapOneCallHandler extends AbstractOpenWeatherMapHandler
if (localWeatherData != null && localWeatherData.getDaily().size() > count) {
org.openhab.binding.openweathermap.internal.dto.onecall.Daily forecastData = localWeatherData.getDaily()
.get(count);
State state = getDailyForecastState(channelId, forecastData, localWeatherData);
logger.debug("Update channel '{}' of group '{}' with new state '{}'.", channelId, channelGroupId, state);
updateState(channelUID, state);
} else {
logger.debug("No weather data available to update channel '{}' of group '{}'.", channelId, channelGroupId);
}
}
private void updateDailyForecastTimeSeries(ChannelUID channelUID) {
String channelId = channelUID.getIdWithoutGroup();
String channelGroupId = channelUID.getGroupId();
if (channelId.equals(CHANNEL_TIME_STAMP)) {
logger.debug("Channel `{}` of group '{}' is no supported time-series channel.", channelId, channelGroupId);
return;
}
OpenWeatherMapOneCallAPIData localWeatherData = weatherData;
if (localWeatherData != null && !localWeatherData.getDaily().isEmpty()) {
List<org.openhab.binding.openweathermap.internal.dto.onecall.Daily> forecastData = localWeatherData
.getDaily();
TimeSeries timeSeries = new TimeSeries(REPLACE);
forecastData.forEach((d) -> {
Instant timestamp = Instant.ofEpochSecond(d.getDt());
State state = getDailyForecastState(channelId, d, localWeatherData);
timeSeries.add(timestamp, state);
});
logger.debug("Update channel '{}' of group '{}' with new time-series '{}'.", channelId, channelGroupId,
timeSeries);
sendTimeSeries(channelUID, timeSeries);
} else {
logger.debug("No weather data available to update channel '{}'.", channelId);
}
}
private State getDailyForecastState(String channelId, Daily forecastData,
OpenWeatherMapOneCallAPIData localWeatherData) {
State state = UnDefType.UNDEF;
Temp temp;
FeelsLikeTemp feelsLike;
Temp temp;
switch (channelId) {
case CHANNEL_TIME_STAMP:
state = getDateTimeTypeState(forecastData.getDt());
@ -664,14 +787,10 @@ public class OpenWeatherMapOneCallHandler extends AbstractOpenWeatherMapHandler
break;
default:
// This should not happen
logger.warn("Unknown channel id {} in onecall daily weather data", channelId);
logger.warn("Unknown channel id {} in OneCall daily weather data", channelId);
break;
}
logger.debug("Update channel '{}' of group '{}' with new state '{}'.", channelId, channelGroupId, state);
updateState(channelUID, state);
} else {
logger.debug("No weather data available to update channel '{}' of group '{}'.", channelId, channelGroupId);
}
return state;
}
/**

View File

@ -130,18 +130,20 @@
<description>Location of weather in geographical coordinates (latitude/longitude/altitude).</description>
</parameter>
<parameter name="forecastDays" type="integer" min="0" max="8" step="1">
<label>Number of Days</label>
<description>Number of days for daily forecast, including the current day.</description>
<label>Number of Daily Forecast Channels</label>
<description>Number of days for daily forecast, including the current day and determining how many daily channels are
created.</description>
<default>6</default>
</parameter>
<parameter name="forecastHours" type="integer" min="0" max="48" step="1">
<label>Number of Hours</label>
<description>Number of hours for hourly forecast.</description>
<label>Number of Hourly Forecast Channels</label>
<description>Number of hours for hourly forecast, determining how many hourly channels are created.</description>
<default>12</default>
</parameter>
<parameter name="forecastMinutes" type="integer" min="0" max="60" step="1">
<label>Number of Minutes</label>
<description>Number of minutes for minutely precipitation forecast.</description>
<label>Number of Minutely Forecast Channels</label>
<description>Number of minutes for minutely precipitation forecast, determining how many minutely channels are
created.</description>
<default>0</default>
</parameter>
<parameter name="numberOfAlerts" type="integer" min="0" max="5" step="1">

View File

@ -74,10 +74,10 @@ thing-type.openweathermap.weather-api.description = Provides access to the OpenW
# thing types config
bridge-type.config.openweathermap.weather-api.apikey.label = API Key
bridge-type.config.openweathermap.weather-api.apikey.description = API key to access the OpenWeatherMap API.
bridge-type.config.openweathermap.weather-api.apiVersion.label = One Call API Version
bridge-type.config.openweathermap.weather-api.apiVersion.description = One Call API version (defaults to 2.5, version 3.0 is available, but needs different subscription).
bridge-type.config.openweathermap.weather-api.apikey.label = API Key
bridge-type.config.openweathermap.weather-api.apikey.description = API key to access the OpenWeatherMap API.
bridge-type.config.openweathermap.weather-api.language.label = Language
bridge-type.config.openweathermap.weather-api.language.description = Language to be used by the OpenWeatherMap API.
bridge-type.config.openweathermap.weather-api.language.option.af = Afrikaans
@ -136,12 +136,12 @@ thing-type.config.openweathermap.onecall-history.historyDay.label = History Day
thing-type.config.openweathermap.onecall-history.historyDay.description = Relative number of days in the past for historical data.
thing-type.config.openweathermap.onecall-history.location.label = Location of Weather
thing-type.config.openweathermap.onecall-history.location.description = Location of weather in geographical coordinates (latitude/longitude/altitude).
thing-type.config.openweathermap.onecall.forecastDays.label = Number of Days
thing-type.config.openweathermap.onecall.forecastDays.description = Number of days for daily forecast, including the current day.
thing-type.config.openweathermap.onecall.forecastHours.label = Number of Hours
thing-type.config.openweathermap.onecall.forecastHours.description = Number of hours for hourly forecast.
thing-type.config.openweathermap.onecall.forecastMinutes.label = Number of Minutes
thing-type.config.openweathermap.onecall.forecastMinutes.description = Number of minutes for minutely precipitation forecast.
thing-type.config.openweathermap.onecall.forecastDays.label = Number of Daily Forecast Channels
thing-type.config.openweathermap.onecall.forecastDays.description = Number of days for daily forecast, including the current day and determining how many daily channels are created.
thing-type.config.openweathermap.onecall.forecastHours.label = Number of Hourly Forecast Channels
thing-type.config.openweathermap.onecall.forecastHours.description = Number of hours for hourly forecast, determining how many hourly channels are created.
thing-type.config.openweathermap.onecall.forecastMinutes.label = Number of Minutely Forecast Channels
thing-type.config.openweathermap.onecall.forecastMinutes.description = Number of minutes for minutely precipitation forecast, determining how many minutely channels are created.
thing-type.config.openweathermap.onecall.location.label = Location of Weather
thing-type.config.openweathermap.onecall.location.description = Location of weather in geographical coordinates (latitude/longitude/altitude).
thing-type.config.openweathermap.onecall.numberOfAlerts.label = Number of Alerts
@ -173,14 +173,20 @@ channel-group-type.openweathermap.oneCallCurrent.label = One Call API Current We
channel-group-type.openweathermap.oneCallCurrent.description = Current weather data from the One Call API.
channel-group-type.openweathermap.oneCallDaily.label = One Call API Daily Forecast
channel-group-type.openweathermap.oneCallDaily.description = Daily weather forecast delivered by the One Call API.
channel-group-type.openweathermap.oneCallDailyTimeSeries.label = One Call API Daily Forecast
channel-group-type.openweathermap.oneCallDailyTimeSeries.description = Daily weather forecast delivered by the One Call API.
channel-group-type.openweathermap.oneCallHistory.label = One Call API Historical Weather
channel-group-type.openweathermap.oneCallHistory.description = Historical weather data from the One Call API at this point in time the given day.
channel-group-type.openweathermap.oneCallHistoryHours.label = One Call API Hourly Historical Weather Data
channel-group-type.openweathermap.oneCallHistoryHours.description = Historical weather data from the One Call API per hour.
channel-group-type.openweathermap.oneCallHourly.label = One Call API Hourly Forecast
channel-group-type.openweathermap.oneCallHourly.description = Hourly weather forecast delivered by the One Call API.
channel-group-type.openweathermap.oneCallHourlyTimeSeries.label = One Call API Hourly Forecast
channel-group-type.openweathermap.oneCallHourlyTimeSeries.description = Hourly weather forecast delivered by the One Call API.
channel-group-type.openweathermap.oneCallMinutely.label = One Call API Minutely Forecast
channel-group-type.openweathermap.oneCallMinutely.description = Minutely precipitation delivered by the One Call API.
channel-group-type.openweathermap.oneCallMinutelyTimeSeries.label = One Call API Minutely Forecast
channel-group-type.openweathermap.oneCallMinutelyTimeSeries.description = Minutely precipitation delivered by the One Call API.
channel-group-type.openweathermap.station.label = Weather Station
channel-group-type.openweathermap.station.description = This is a weather station.
channel-group-type.openweathermap.station.channel.location.description = Location of the weather station or the city.

View File

@ -169,6 +169,14 @@
</channels>
</channel-group-type>
<channel-group-type id="oneCallMinutelyTimeSeries">
<label>One Call API Minutely Forecast</label>
<description>Minutely precipitation delivered by the One Call API.</description>
<channels>
<channel id="precipitation" typeId="precipitation"/>
</channels>
</channel-group-type>
<channel-group-type id="oneCallMinutely">
<label>One Call API Minutely Forecast</label>
<description>Minutely precipitation delivered by the One Call API.</description>
@ -178,6 +186,30 @@
</channels>
</channel-group-type>
<channel-group-type id="oneCallHourlyTimeSeries">
<label>One Call API Hourly Forecast</label>
<description>Hourly weather forecast delivered by the One Call API.</description>
<channels>
<channel id="condition" typeId="condition"/>
<channel id="condition-id" typeId="condition-id"/>
<channel id="icon" typeId="condition-icon"/>
<channel id="icon-id" typeId="condition-icon-id"/>
<channel id="temperature" typeId="system.outdoor-temperature"/>
<channel id="apparent-temperature" typeId="apparent-temperature"/>
<channel id="pressure" typeId="system.barometric-pressure"/>
<channel id="humidity" typeId="system.atmospheric-humidity"/>
<channel id="dew-point" typeId="dew-point"/>
<channel id="wind-speed" typeId="system.wind-speed"/>
<channel id="wind-direction" typeId="system.wind-direction"/>
<channel id="gust-speed" typeId="gust-speed"/>
<channel id="cloudiness" typeId="cloudiness"/>
<channel id="precip-probability" typeId="precip-probability"/>
<channel id="rain" typeId="rain"/>
<channel id="snow" typeId="snow"/>
<channel id="visibility" typeId="visibility"/>
</channels>
</channel-group-type>
<channel-group-type id="oneCallHourly">
<label>One Call API Hourly Forecast</label>
<description>Hourly weather forecast delivered by the One Call API.</description>
@ -203,6 +235,40 @@
</channels>
</channel-group-type>
<channel-group-type id="oneCallDailyTimeSeries">
<label>One Call API Daily Forecast</label>
<description>Daily weather forecast delivered by the One Call API.</description>
<channels>
<channel id="sunrise" typeId="sunrise"/>
<channel id="sunset" typeId="sunset"/>
<channel id="condition" typeId="condition"/>
<channel id="condition-id" typeId="condition-id"/>
<channel id="icon" typeId="condition-icon"/>
<channel id="icon-id" typeId="condition-icon-id"/>
<channel id="morning-temperature" typeId="morning-temperature"/>
<channel id="day-temperature" typeId="day-temperature"/>
<channel id="evening-temperature" typeId="evening-temperature"/>
<channel id="night-temperature" typeId="night-temperature"/>
<channel id="min-temperature" typeId="forecasted-min-outdoor-temperature"/>
<channel id="max-temperature" typeId="forecasted-max-outdoor-temperature"/>
<channel id="apparent-morning" typeId="apparent-morning"/>
<channel id="apparent-day" typeId="apparent-day"/>
<channel id="apparent-evening" typeId="apparent-evening"/>
<channel id="apparent-night" typeId="apparent-night"/>
<channel id="pressure" typeId="system.barometric-pressure"/>
<channel id="humidity" typeId="system.atmospheric-humidity"/>
<channel id="dew-point" typeId="dew-point"/>
<channel id="wind-speed" typeId="system.wind-speed"/>
<channel id="wind-direction" typeId="system.wind-direction"/>
<channel id="gust-speed" typeId="gust-speed"/>
<channel id="cloudiness" typeId="cloudiness"/>
<channel id="uvindex" typeId="forecasted-uvindex"/>
<channel id="precip-probability" typeId="precip-probability"/>
<channel id="rain" typeId="rain"/>
<channel id="snow" typeId="snow"/>
</channels>
</channel-group-type>
<channel-group-type id="oneCallDaily">
<label>One Call API Daily Forecast</label>
<description>Daily weather forecast delivered by the One Call API.</description>

View File

@ -142,6 +142,9 @@
<channel-groups>
<channel-group id="current" typeId="oneCallCurrent"/>
<channel-group id="forecastMinutely" typeId="oneCallMinutelyTimeSeries"/>
<channel-group id="forecastMinutes01" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes02" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes03" typeId="oneCallMinutely"/>
@ -208,6 +211,8 @@
<channel-group id="forecastMinutes59" typeId="oneCallMinutely"/>
<channel-group id="forecastMinutes60" typeId="oneCallMinutely"/>
<channel-group id="forecastHourly" typeId="oneCallHourlyTimeSeries"/>
<channel-group id="forecastHours01" typeId="oneCallHourly"/>
<channel-group id="forecastHours02" typeId="oneCallHourly"/>
<channel-group id="forecastHours03" typeId="oneCallHourly"/>
@ -233,6 +238,8 @@
<channel-group id="forecastHours23" typeId="oneCallHourly"/>
<channel-group id="forecastHours24" typeId="oneCallHourly"/>
<channel-group id="forecastDaily" typeId="oneCallDailyTimeSeries"/>
<channel-group id="forecastToday" typeId="oneCallDaily">
<label>One Call API Todays Forecast</label>
<description>This is the weather forecast for today from the one call API.</description>
@ -267,6 +274,9 @@
</channel-group>
</channel-groups>
<properties>
<property name="thingTypeVersion">1</property>
</properties>
<representation-property>location</representation-property>
<config-description-ref uri="thing-type:openweathermap:onecall"/>

View File

@ -0,0 +1,148 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<update:update-descriptions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:update="https://openhab.org/schemas/update-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/update-description/v1.0.0 https://openhab.org/schemas/update-description-1.0.0.xsd">
<thing-type uid="openweathermap:onecall">
<instruction-set targetVersion="1">
<add-channel id="precipitation" groupIds="forecastMinutely">
<type>openweathermap:precipitation</type>
</add-channel>
<add-channel id="condition" groupIds="forecastHourly">
<type>openweathermap:condition</type>
</add-channel>
<add-channel id="condition-id" groupIds="forecastHourly">
<type>openweathermap:condition-id</type>
</add-channel>
<add-channel id="icon" groupIds="forecastHourly">
<type>openweathermap:condition-icon</type>
</add-channel>
<add-channel id="icon-id" groupIds="forecastHourly">
<type>openweathermap:condition-icon-id</type>
</add-channel>
<add-channel id="temperature" groupIds="forecastHourly">
<type>system:outdoor-temperature</type>
</add-channel>
<add-channel id="apperent-temperature" groupIds="forecastHourly">
<type>openweathermap:apparent-temperature</type>
</add-channel>
<add-channel id="pressure" groupIds="forecastHourly">
<type>system:barometric-pressure</type>
</add-channel>
<add-channel id="humidity" groupIds="forecastHourly">
<type>system:atmospheric-humidity</type>
</add-channel>
<add-channel id="dew-point" groupIds="forecastHourly">
<type>openweathermap:dew-point</type>
</add-channel>
<add-channel id="wind-speed" groupIds="forecastHourly">
<type>system:wind-speed</type>
</add-channel>
<add-channel id="wind-direction" groupIds="forecastHourly">
<type>system:wind-direction</type>
</add-channel>
<add-channel id="gust-speed" groupIds="forecastHourly">
<type>openweathermap:gust-speed</type>
</add-channel>
<add-channel id="cloudiness" groupIds="forecastHourly">
<type>openweathermap:cloudiness</type>
</add-channel>
<add-channel id="precip-probability" groupIds="forecastHourly">
<type>openweathermap:precip-probability</type>
</add-channel>
<add-channel id="rain" groupIds="forecastHourly">
<type>openweathermap:rain</type>
</add-channel>
<add-channel id="snow" groupIds="forecastHourly">
<type>openweathermap:snow</type>
</add-channel>
<add-channel id="visbility" groupIds="forecastHourly">
<type>openweathermap:visibility</type>
</add-channel>
<add-channel id="sunrise" groupIds="forecastDaily">
<type>openweathermap:sunrise</type>
</add-channel>
<add-channel id="sunset" groupIds="forecastDaily">
<type>openweathermap:sunset</type>
</add-channel>
<add-channel id="condition" groupIds="forecastDaily">
<type>openweathermap:condition</type>
</add-channel>
<add-channel id="condition-id" groupIds="forecastDaily">
<type>openweathermap:condition-id</type>
</add-channel>
<add-channel id="icon" groupIds="forecastDaily">
<type>openweathermap:condition-icon</type>
</add-channel>
<add-channel id="icon-id" groupIds="forecastDaily">
<type>openweathermap:condition-icon-id</type>
</add-channel>
<add-channel id="morning-temperature" groupIds="forecastDaily">
<type>openweathermap:morning-temperature</type>
</add-channel>
<add-channel id="day-temperature" groupIds="forecastDaily">
<type>openweathermap:day-temperature</type>
</add-channel>
<add-channel id="evening-temperature" groupIds="forecastDaily">
<type>openweathermap:evening-temperature</type>
</add-channel>
<add-channel id="night-temperature" groupIds="forecastDaily">
<type>openweathermap:night-temperature</type>
</add-channel>
<add-channel id="min-temperature" groupIds="forecastDaily">
<type>openweathermap:forecasted-min-outdoor-temperature</type>
</add-channel>
<add-channel id="max-temperature" groupIds="forecastDaily">
<type>openweathermap:forecasted-max-outdoor-temperature</type>
</add-channel>
<add-channel id="apparent-morning" groupIds="forecastDaily">
<type>openweathermap:apparent-morning</type>
</add-channel>
<add-channel id="apparent-day" groupIds="forecastDaily">
<type>openweathermap:apparent-day</type>
</add-channel>
<add-channel id="apparent-evening" groupIds="forecastDaily">
<type>openweathermap:apparent-evening</type>
</add-channel>
<add-channel id="apparent-night" groupIds="forecastDaily">
<type>openweathermap:apparent-night</type>
</add-channel>
<add-channel id="pressure" groupIds="forecastDaily">
<type>system:barometric-pressure</type>
</add-channel>
<add-channel id="humidity" groupIds="forecastDaily">
<type>system:atmospheric-humidity</type>
</add-channel>
<add-channel id="dew-point" groupIds="forecastDaily">
<type>openweathermap:dew-point</type>
</add-channel>
<add-channel id="wind-speed" groupIds="forecastDaily">
<type>system:wind-speed</type>
</add-channel>
<add-channel id="wind-direction" groupIds="forecastDaily">
<type>system:wind-direction</type>
</add-channel>
<add-channel id="gust-speed" groupIds="forecastDaily">
<type>openweathermap:gust-speed</type>
</add-channel>
<add-channel id="cloudiness" groupIds="forecastDaily">
<type>openweathermap:cloudiness</type>
</add-channel>
<add-channel id="uvindex" groupIds="forecastDaily">
<type>openweathermap:forecasted-uvindex</type>
</add-channel>
<add-channel id="precip-probability" groupIds="forecastDaily">
<type>openweathermap:precip-probability</type>
</add-channel>
<add-channel id="rain" groupIds="forecastDaily">
<type>openweathermap:rain</type>
</add-channel>
<add-channel id="snow" groupIds="forecastDaily">
<type>openweathermap:snow</type>
</add-channel>
</instruction-set>
</thing-type>
</update:update-descriptions>