[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
7 changed files with 655 additions and 276 deletions

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,79 +483,7 @@ 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 = UnDefType.UNDEF;
switch (channelId) {
case CHANNEL_TIME_STAMP:
state = getDateTimeTypeState(forecastData.getDt());
break;
case CHANNEL_CONDITION:
if (!forecastData.getWeather().isEmpty()) {
state = getStringTypeState(forecastData.getWeather().get(0).getDescription());
}
break;
case CHANNEL_CONDITION_ID:
if (!forecastData.getWeather().isEmpty()) {
state = getStringTypeState(Integer.toString(forecastData.getWeather().get(0).getId()));
}
break;
case CHANNEL_CONDITION_ICON:
if (!forecastData.getWeather().isEmpty()) {
state = getRawTypeState(
OpenWeatherMapConnection.getWeatherIcon(forecastData.getWeather().get(0).getIcon()));
}
break;
case CHANNEL_CONDITION_ICON_ID:
if (!forecastData.getWeather().isEmpty()) {
state = getStringTypeState(forecastData.getWeather().get(0).getIcon());
}
break;
case CHANNEL_TEMPERATURE:
state = getQuantityTypeState(forecastData.getTemp(), CELSIUS);
break;
case CHANNEL_APPARENT_TEMPERATURE:
state = getQuantityTypeState(forecastData.getFeelsLike(), CELSIUS);
break;
case CHANNEL_PRESSURE:
state = getQuantityTypeState(forecastData.getPressure(), HECTO(PASCAL));
break;
case CHANNEL_HUMIDITY:
state = getQuantityTypeState(forecastData.getHumidity(), PERCENT);
break;
case CHANNEL_DEW_POINT:
state = getQuantityTypeState(forecastData.getDewPoint(), CELSIUS);
break;
case CHANNEL_WIND_SPEED:
state = getQuantityTypeState(forecastData.getWindSpeed(), METRE_PER_SECOND);
break;
case CHANNEL_WIND_DIRECTION:
state = getQuantityTypeState(forecastData.getWindDeg(), DEGREE_ANGLE);
break;
case CHANNEL_GUST_SPEED:
state = getQuantityTypeState(forecastData.getWindGust(), METRE_PER_SECOND);
break;
case CHANNEL_CLOUDINESS:
state = getQuantityTypeState(forecastData.getClouds(), PERCENT);
break;
case CHANNEL_VISIBILITY:
State tempstate = new QuantityType<>(localWeatherData.getCurrent().getVisibility(), METRE)
.toUnit(KILO(METRE));
state = (tempstate == null ? state : tempstate);
case CHANNEL_PRECIP_PROBABILITY:
state = getQuantityTypeState(forecastData.getPop() * 100.0, PERCENT);
break;
case CHANNEL_RAIN:
Precipitation rain = forecastData.getRain();
state = getQuantityTypeState(rain == null ? 0 : rain.get1h(), MILLI(METRE));
break;
case CHANNEL_SNOW:
Precipitation snow = forecastData.getSnow();
state = getQuantityTypeState(snow == null ? 0 : snow.get1h(), MILLI(METRE));
break;
default:
// This should not happen
logger.warn("Unknown channel id {} in onecall hourly weather data", channelId);
break;
}
State state = getHourlyForecastState(channelId, forecastData, localWeatherData);
logger.debug("Update channel '{}' of group '{}' with new state '{}'.", channelId, channelGroupId, state);
updateState(channelUID, state);
} else {
@@ -512,7 +492,115 @@ public class OpenWeatherMapOneCallHandler extends AbstractOpenWeatherMapHandler
}
/**
* Update the channel from the last OpenWeatherMap data retrieved.
* 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:
state = getDateTimeTypeState(forecastData.getDt());
break;
case CHANNEL_CONDITION:
if (!forecastData.getWeather().isEmpty()) {
state = getStringTypeState(forecastData.getWeather().get(0).getDescription());
}
break;
case CHANNEL_CONDITION_ID:
if (!forecastData.getWeather().isEmpty()) {
state = getStringTypeState(Integer.toString(forecastData.getWeather().get(0).getId()));
}
break;
case CHANNEL_CONDITION_ICON:
if (!forecastData.getWeather().isEmpty()) {
state = getRawTypeState(
OpenWeatherMapConnection.getWeatherIcon(forecastData.getWeather().get(0).getIcon()));
}
break;
case CHANNEL_CONDITION_ICON_ID:
if (!forecastData.getWeather().isEmpty()) {
state = getStringTypeState(forecastData.getWeather().get(0).getIcon());
}
break;
case CHANNEL_TEMPERATURE:
state = getQuantityTypeState(forecastData.getTemp(), CELSIUS);
break;
case CHANNEL_APPARENT_TEMPERATURE:
state = getQuantityTypeState(forecastData.getFeelsLike(), CELSIUS);
break;
case CHANNEL_PRESSURE:
state = getQuantityTypeState(forecastData.getPressure(), HECTO(PASCAL));
break;
case CHANNEL_HUMIDITY:
state = getQuantityTypeState(forecastData.getHumidity(), PERCENT);
break;
case CHANNEL_DEW_POINT:
state = getQuantityTypeState(forecastData.getDewPoint(), CELSIUS);
break;
case CHANNEL_WIND_SPEED:
state = getQuantityTypeState(forecastData.getWindSpeed(), METRE_PER_SECOND);
break;
case CHANNEL_WIND_DIRECTION:
state = getQuantityTypeState(forecastData.getWindDeg(), DEGREE_ANGLE);
break;
case CHANNEL_GUST_SPEED:
state = getQuantityTypeState(forecastData.getWindGust(), METRE_PER_SECOND);
break;
case CHANNEL_CLOUDINESS:
state = getQuantityTypeState(forecastData.getClouds(), PERCENT);
break;
case CHANNEL_VISIBILITY:
State tempstate = new QuantityType<>(localWeatherData.getCurrent().getVisibility(), METRE)
.toUnit(KILO(METRE));
state = (tempstate == null ? state : tempstate);
case CHANNEL_PRECIP_PROBABILITY:
state = getQuantityTypeState(forecastData.getPop() * 100.0, PERCENT);
break;
case CHANNEL_RAIN:
Precipitation rain = forecastData.getRain();
state = getQuantityTypeState(rain == null ? 0 : rain.get1h(), MILLI(METRE));
break;
case CHANNEL_SNOW:
Precipitation snow = forecastData.getSnow();
state = getQuantityTypeState(snow == null ? 0 : snow.get1h(), MILLI(METRE));
break;
default:
// This should not happen
logger.warn("Unknown channel id {} in OneCall hourly weather data", channelId);
break;
}
return state;
}
/**
* 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,143 +618,7 @@ 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 = UnDefType.UNDEF;
Temp temp;
FeelsLikeTemp feelsLike;
switch (channelId) {
case CHANNEL_TIME_STAMP:
state = getDateTimeTypeState(forecastData.getDt());
break;
case CHANNEL_SUNRISE:
state = getDateTimeTypeState(forecastData.getSunrise());
break;
case CHANNEL_SUNSET:
state = getDateTimeTypeState(forecastData.getSunset());
break;
case CHANNEL_CONDITION:
if (!forecastData.getWeather().isEmpty()) {
state = getStringTypeState(forecastData.getWeather().get(0).getDescription());
}
break;
case CHANNEL_CONDITION_ID:
if (!forecastData.getWeather().isEmpty()) {
state = getStringTypeState(Integer.toString(forecastData.getWeather().get(0).getId()));
}
break;
case CHANNEL_CONDITION_ICON:
if (!forecastData.getWeather().isEmpty()) {
state = getRawTypeState(
OpenWeatherMapConnection.getWeatherIcon(forecastData.getWeather().get(0).getIcon()));
}
break;
case CHANNEL_CONDITION_ICON_ID:
if (!forecastData.getWeather().isEmpty()) {
state = getStringTypeState(forecastData.getWeather().get(0).getIcon());
}
break;
case CHANNEL_MIN_TEMPERATURE:
temp = forecastData.getTemp();
if (temp != null) {
state = getQuantityTypeState(temp.getMin(), CELSIUS);
}
break;
case CHANNEL_MAX_TEMPERATURE:
temp = forecastData.getTemp();
if (temp != null) {
state = getQuantityTypeState(temp.getMax(), CELSIUS);
}
break;
case CHANNEL_MORNING_TEMPERATURE:
temp = forecastData.getTemp();
if (temp != null) {
state = getQuantityTypeState(temp.getMorn(), CELSIUS);
}
break;
case CHANNEL_DAY_TEMPERATURE:
temp = forecastData.getTemp();
if (temp != null) {
state = getQuantityTypeState(temp.getDay(), CELSIUS);
}
break;
case CHANNEL_EVENING_TEMPERATURE:
temp = forecastData.getTemp();
if (temp != null) {
state = getQuantityTypeState(temp.getEve(), CELSIUS);
}
break;
case CHANNEL_NIGHT_TEMPERATURE:
temp = forecastData.getTemp();
if (temp != null) {
state = getQuantityTypeState(temp.getNight(), CELSIUS);
}
break;
case CHANNEL_APPARENT_DAY:
feelsLike = forecastData.getFeelsLike();
if (feelsLike != null) {
state = getQuantityTypeState(feelsLike.getDay(), CELSIUS);
}
break;
case CHANNEL_APPARENT_MORNING:
feelsLike = forecastData.getFeelsLike();
if (feelsLike != null) {
state = getQuantityTypeState(feelsLike.getMorn(), CELSIUS);
}
break;
case CHANNEL_APPARENT_EVENING:
feelsLike = forecastData.getFeelsLike();
if (feelsLike != null) {
state = getQuantityTypeState(feelsLike.getEve(), CELSIUS);
}
break;
case CHANNEL_APPARENT_NIGHT:
feelsLike = forecastData.getFeelsLike();
if (feelsLike != null) {
state = getQuantityTypeState(feelsLike.getNight(), CELSIUS);
}
break;
case CHANNEL_PRESSURE:
state = getQuantityTypeState(forecastData.getPressure(), HECTO(PASCAL));
break;
case CHANNEL_HUMIDITY:
state = getQuantityTypeState(forecastData.getHumidity(), PERCENT);
break;
case CHANNEL_WIND_SPEED:
state = getQuantityTypeState(forecastData.getWindSpeed(), METRE_PER_SECOND);
break;
case CHANNEL_WIND_DIRECTION:
state = getQuantityTypeState(forecastData.getWindDeg(), DEGREE_ANGLE);
break;
case CHANNEL_GUST_SPEED:
state = getQuantityTypeState(forecastData.getWindGust(), METRE_PER_SECOND);
break;
case CHANNEL_CLOUDINESS:
state = getQuantityTypeState(forecastData.getClouds(), PERCENT);
break;
case CHANNEL_DEW_POINT:
state = getQuantityTypeState(forecastData.getDewPoint(), CELSIUS);
break;
case CHANNEL_UVINDEX:
state = getDecimalTypeState(forecastData.getUvi());
break;
case CHANNEL_VISIBILITY:
State tempstate = new QuantityType<>(localWeatherData.getCurrent().getVisibility(), METRE)
.toUnit(KILO(METRE));
state = (tempstate == null ? state : tempstate);
case CHANNEL_PRECIP_PROBABILITY:
state = getQuantityTypeState(forecastData.getPop() * 100.0, PERCENT);
break;
case CHANNEL_RAIN:
state = getQuantityTypeState(forecastData.getRain(), MILLI(METRE));
break;
case CHANNEL_SNOW:
state = getQuantityTypeState(forecastData.getSnow(), MILLI(METRE));
break;
default:
// This should not happen
logger.warn("Unknown channel id {} in onecall daily weather data", channelId);
break;
}
State state = getDailyForecastState(channelId, forecastData, localWeatherData);
logger.debug("Update channel '{}' of group '{}' with new state '{}'.", channelId, channelGroupId, state);
updateState(channelUID, state);
} else {
@@ -674,6 +626,173 @@ public class OpenWeatherMapOneCallHandler extends AbstractOpenWeatherMapHandler
}
}
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;
FeelsLikeTemp feelsLike;
Temp temp;
switch (channelId) {
case CHANNEL_TIME_STAMP:
state = getDateTimeTypeState(forecastData.getDt());
break;
case CHANNEL_SUNRISE:
state = getDateTimeTypeState(forecastData.getSunrise());
break;
case CHANNEL_SUNSET:
state = getDateTimeTypeState(forecastData.getSunset());
break;
case CHANNEL_CONDITION:
if (!forecastData.getWeather().isEmpty()) {
state = getStringTypeState(forecastData.getWeather().get(0).getDescription());
}
break;
case CHANNEL_CONDITION_ID:
if (!forecastData.getWeather().isEmpty()) {
state = getStringTypeState(Integer.toString(forecastData.getWeather().get(0).getId()));
}
break;
case CHANNEL_CONDITION_ICON:
if (!forecastData.getWeather().isEmpty()) {
state = getRawTypeState(
OpenWeatherMapConnection.getWeatherIcon(forecastData.getWeather().get(0).getIcon()));
}
break;
case CHANNEL_CONDITION_ICON_ID:
if (!forecastData.getWeather().isEmpty()) {
state = getStringTypeState(forecastData.getWeather().get(0).getIcon());
}
break;
case CHANNEL_MIN_TEMPERATURE:
temp = forecastData.getTemp();
if (temp != null) {
state = getQuantityTypeState(temp.getMin(), CELSIUS);
}
break;
case CHANNEL_MAX_TEMPERATURE:
temp = forecastData.getTemp();
if (temp != null) {
state = getQuantityTypeState(temp.getMax(), CELSIUS);
}
break;
case CHANNEL_MORNING_TEMPERATURE:
temp = forecastData.getTemp();
if (temp != null) {
state = getQuantityTypeState(temp.getMorn(), CELSIUS);
}
break;
case CHANNEL_DAY_TEMPERATURE:
temp = forecastData.getTemp();
if (temp != null) {
state = getQuantityTypeState(temp.getDay(), CELSIUS);
}
break;
case CHANNEL_EVENING_TEMPERATURE:
temp = forecastData.getTemp();
if (temp != null) {
state = getQuantityTypeState(temp.getEve(), CELSIUS);
}
break;
case CHANNEL_NIGHT_TEMPERATURE:
temp = forecastData.getTemp();
if (temp != null) {
state = getQuantityTypeState(temp.getNight(), CELSIUS);
}
break;
case CHANNEL_APPARENT_DAY:
feelsLike = forecastData.getFeelsLike();
if (feelsLike != null) {
state = getQuantityTypeState(feelsLike.getDay(), CELSIUS);
}
break;
case CHANNEL_APPARENT_MORNING:
feelsLike = forecastData.getFeelsLike();
if (feelsLike != null) {
state = getQuantityTypeState(feelsLike.getMorn(), CELSIUS);
}
break;
case CHANNEL_APPARENT_EVENING:
feelsLike = forecastData.getFeelsLike();
if (feelsLike != null) {
state = getQuantityTypeState(feelsLike.getEve(), CELSIUS);
}
break;
case CHANNEL_APPARENT_NIGHT:
feelsLike = forecastData.getFeelsLike();
if (feelsLike != null) {
state = getQuantityTypeState(feelsLike.getNight(), CELSIUS);
}
break;
case CHANNEL_PRESSURE:
state = getQuantityTypeState(forecastData.getPressure(), HECTO(PASCAL));
break;
case CHANNEL_HUMIDITY:
state = getQuantityTypeState(forecastData.getHumidity(), PERCENT);
break;
case CHANNEL_WIND_SPEED:
state = getQuantityTypeState(forecastData.getWindSpeed(), METRE_PER_SECOND);
break;
case CHANNEL_WIND_DIRECTION:
state = getQuantityTypeState(forecastData.getWindDeg(), DEGREE_ANGLE);
break;
case CHANNEL_GUST_SPEED:
state = getQuantityTypeState(forecastData.getWindGust(), METRE_PER_SECOND);
break;
case CHANNEL_CLOUDINESS:
state = getQuantityTypeState(forecastData.getClouds(), PERCENT);
break;
case CHANNEL_DEW_POINT:
state = getQuantityTypeState(forecastData.getDewPoint(), CELSIUS);
break;
case CHANNEL_UVINDEX:
state = getDecimalTypeState(forecastData.getUvi());
break;
case CHANNEL_VISIBILITY:
State tempstate = new QuantityType<>(localWeatherData.getCurrent().getVisibility(), METRE)
.toUnit(KILO(METRE));
state = (tempstate == null ? state : tempstate);
case CHANNEL_PRECIP_PROBABILITY:
state = getQuantityTypeState(forecastData.getPop() * 100.0, PERCENT);
break;
case CHANNEL_RAIN:
state = getQuantityTypeState(forecastData.getRain(), MILLI(METRE));
break;
case CHANNEL_SNOW:
state = getQuantityTypeState(forecastData.getSnow(), MILLI(METRE));
break;
default:
// This should not happen
logger.warn("Unknown channel id {} in OneCall daily weather data", channelId);
break;
}
return state;
}
/**
* Update the channel from the last OpenWeaterhMap data retrieved.
*

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>