diff --git a/bundles/org.openhab.binding.fmiweather/README.md b/bundles/org.openhab.binding.fmiweather/README.md
index be0724a8784..94aed6ca50f 100644
--- a/bundles/org.openhab.binding.fmiweather/README.md
+++ b/bundles/org.openhab.binding.fmiweather/README.md
@@ -2,8 +2,12 @@
This binding integrates to [the Finnish Meteorological Institute (FMI) Open Data API](https://en.ilmatieteenlaitos.fi/open-data).
-Binding provides access to weather observations from FMI weather stations and [HARMONIE weather forecast model](https://en.ilmatieteenlaitos.fi/weather-forecast-models) forecasts.
+The binding provides access to weather observations from FMI weather stations and FMI weather forecasts.
Forecast covers "northern Europe" (Finland, Baltics, Scandinavia, some parts of surrounding countries), see [coverage map in the documentation](https://en.ilmatieteenlaitos.fi/weather-forecast-models).
+The binding supports two different forecast queries:
+
+- [HARMONIE weather forecast model](https://en.ilmatieteenlaitos.fi/weather-forecast-models), which is one of the weather models that meteorologists use in their work.
+- An edited query providing the official FMI forecast, which is often more accurate since it's edited by meteorologists who combine several different weather models and their experience to produce the official forecast.
![example of things](doc/images/fmi-example-things.png)
@@ -36,9 +40,10 @@ The binding automatically discovers weather stations and forecasts for nearby pl
### `forecast` Thing Configuration
-| Parameter | Type | Required | Description | Example |
-| ---------- | ---- | -------- | ---------------------------------------------------------------------------------------------------- | --------------------------------- |
+| Parameter | Type | Required | Description | Example |
+| ---------- | ---- | -------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------- |
| `location` | text | ✓ | Latitude longitude location for the forecast. The parameter is given in format `LATITUDE,LONGITUDE`. | `"60.192059, 24.945831"` for Helsinki |
+| `query` | text | | Stored query for official FMI forecast, either `harmonie` or `edited`. | |
## Channels
diff --git a/bundles/org.openhab.binding.fmiweather/src/main/java/org/openhab/binding/fmiweather/internal/AbstractWeatherHandler.java b/bundles/org.openhab.binding.fmiweather/src/main/java/org/openhab/binding/fmiweather/internal/AbstractWeatherHandler.java
index 0aaf824e399..57426a9cdb7 100644
--- a/bundles/org.openhab.binding.fmiweather/src/main/java/org/openhab/binding/fmiweather/internal/AbstractWeatherHandler.java
+++ b/bundles/org.openhab.binding.fmiweather/src/main/java/org/openhab/binding/fmiweather/internal/AbstractWeatherHandler.java
@@ -138,9 +138,6 @@ public abstract class AbstractWeatherHandler extends BaseThingHandler {
if (retry < RETRIES) {
try {
response = client.query(getRequest(), TIMEOUT_MILLIS);
- } catch (FMIUnexpectedResponseException e) {
- handleError(e, retry);
- return;
} catch (FMIResponseException e) {
handleError(e, retry);
return;
diff --git a/bundles/org.openhab.binding.fmiweather/src/main/java/org/openhab/binding/fmiweather/internal/ForecastWeatherHandler.java b/bundles/org.openhab.binding.fmiweather/src/main/java/org/openhab/binding/fmiweather/internal/ForecastWeatherHandler.java
index 03e78ef778b..019d8ed3d9a 100644
--- a/bundles/org.openhab.binding.fmiweather/src/main/java/org/openhab/binding/fmiweather/internal/ForecastWeatherHandler.java
+++ b/bundles/org.openhab.binding.fmiweather/src/main/java/org/openhab/binding/fmiweather/internal/ForecastWeatherHandler.java
@@ -37,6 +37,7 @@ import org.openhab.binding.fmiweather.internal.client.LatLon;
import org.openhab.binding.fmiweather.internal.client.Location;
import org.openhab.binding.fmiweather.internal.client.Request;
import org.openhab.binding.fmiweather.internal.client.exception.FMIUnexpectedResponseException;
+import org.openhab.binding.fmiweather.internal.config.ForecastConfiguration;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
@@ -82,6 +83,7 @@ public class ForecastWeatherHandler extends AbstractWeatherHandler {
}
private @NonNullByDefault({}) LatLon location;
+ private String query = "";
public ForecastWeatherHandler(Thing thing) {
super(thing);
@@ -91,27 +93,23 @@ public class ForecastWeatherHandler extends AbstractWeatherHandler {
@Override
public void initialize() {
- try {
- Object location = getConfig().get(BindingConstants.LOCATION);
- if (location == null) {
- logger.debug("Location not set for thing {} -- aborting initialization.", getThing().getUID());
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
- String.format("location parameter not set"));
- return;
- }
- String latlon = location.toString();
- String[] split = latlon.split(",");
- if (split.length != 2) {
- throw new NumberFormatException(String.format(
- "Expecting location parameter to have latitude and longitude separated by comma (LATITUDE,LONGITUDE). Found %d values instead.",
- split.length));
- }
- this.location = new LatLon(new BigDecimal(split[0].trim()), new BigDecimal(split[1].trim()));
- super.initialize();
- } catch (NumberFormatException e) {
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, String.format(
- "location parameter should be in format LATITUDE,LONGITUDE. Error details: %s", e.getMessage()));
+ ForecastConfiguration config = getConfigAs(ForecastConfiguration.class);
+ String location = config.location;
+ if (location.isBlank()) {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "location parameter not set");
+ return;
}
+ String[] split = location.split(",");
+ if (split.length != 2) {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, String.format(
+ "location parameter should have latitude and longitude separated by comma (LATITUDE,LONGITUDE). Found %d values instead",
+ split.length));
+ return;
+ }
+ this.location = new LatLon(new BigDecimal(split[0].trim()), new BigDecimal(split[1].trim()));
+ query = config.query;
+
+ super.initialize();
}
@Override
@@ -123,7 +121,7 @@ public class ForecastWeatherHandler extends AbstractWeatherHandler {
@Override
protected Request getRequest() {
long now = Instant.now().getEpochSecond();
- return new ForecastRequest(location, floorToEvenMinutes(now, QUERY_RESOLUTION_MINUTES),
+ return new ForecastRequest(location, query, floorToEvenMinutes(now, QUERY_RESOLUTION_MINUTES),
ceilToEvenMinutes(now + TimeUnit.HOURS.toSeconds(FORECAST_HORIZON_HOURS), QUERY_RESOLUTION_MINUTES),
QUERY_RESOLUTION_MINUTES);
}
diff --git a/bundles/org.openhab.binding.fmiweather/src/main/java/org/openhab/binding/fmiweather/internal/client/Client.java b/bundles/org.openhab.binding.fmiweather/src/main/java/org/openhab/binding/fmiweather/internal/client/Client.java
index 4b9f4b7715c..6cd22851e05 100644
--- a/bundles/org.openhab.binding.fmiweather/src/main/java/org/openhab/binding/fmiweather/internal/client/Client.java
+++ b/bundles/org.openhab.binding.fmiweather/src/main/java/org/openhab/binding/fmiweather/internal/client/Client.java
@@ -133,10 +133,12 @@ public class Client {
throws FMIExceptionReportException, FMIUnexpectedResponseException, FMIIOException {
try {
String url = request.toUrl();
+ logger.trace("GET request for {}", url);
String responseText = HttpUtil.executeUrl("GET", url, timeoutMillis);
if (responseText == null) {
throw new FMIIOException(String.format("HTTP error with %s", request.toUrl()));
}
+ logger.trace("Response content: '{}'", responseText);
FMIResponse response = parseMultiPointCoverageXml(responseText);
logger.debug("Request {} translated to url {}. Response: {}", request, url, response);
return response;
diff --git a/bundles/org.openhab.binding.fmiweather/src/main/java/org/openhab/binding/fmiweather/internal/client/ForecastRequest.java b/bundles/org.openhab.binding.fmiweather/src/main/java/org/openhab/binding/fmiweather/internal/client/ForecastRequest.java
index 359a757b050..cd494034d4b 100644
--- a/bundles/org.openhab.binding.fmiweather/src/main/java/org/openhab/binding/fmiweather/internal/client/ForecastRequest.java
+++ b/bundles/org.openhab.binding.fmiweather/src/main/java/org/openhab/binding/fmiweather/internal/client/ForecastRequest.java
@@ -13,6 +13,7 @@
package org.openhab.binding.fmiweather.internal.client;
import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.binding.fmiweather.internal.config.ForecastConfiguration;
/**
* Request for weather forecasts
@@ -23,7 +24,8 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
@NonNullByDefault
public class ForecastRequest extends Request {
- public static final String STORED_QUERY_ID = "fmi::forecast::harmonie::surface::point::multipointcoverage";
+ public static final String STORED_QUERY_ID_HARMONIE = "fmi::forecast::harmonie::surface::point::multipointcoverage";
+ public static final String STORED_QUERY_ID_EDITED = "fmi::forecast::edited::weather::scandinavia::point::multipointcoverage";
// For description of variables: http://opendata.fmi.fi/meta?observableProperty=forecast
public static final String PARAM_TEMPERATURE = "Temperature";
@@ -39,7 +41,12 @@ public class ForecastRequest extends Request {
PARAM_WIND_SPEED, PARAM_WIND_GUST, PARAM_PRESSURE, PARAM_PRECIPITATION_1H, PARAM_TOTAL_CLOUD_COVER,
PARAM_WEATHER_SYMBOL };
- public ForecastRequest(QueryParameter location, long startEpoch, long endEpoch, long timestepMinutes) {
- super(STORED_QUERY_ID, location, startEpoch, endEpoch, timestepMinutes, PARAMETERS);
+ public ForecastRequest(QueryParameter location, String query, long startEpoch, long endEpoch,
+ long timestepMinutes) {
+ super(switch (query) {
+ case ForecastConfiguration.QUERY_HARMONIE -> STORED_QUERY_ID_HARMONIE;
+ case ForecastConfiguration.QUERY_EDITED -> STORED_QUERY_ID_EDITED;
+ default -> throw new IllegalArgumentException("Invalid query parameter '%s'".formatted(query));
+ }, location, startEpoch, endEpoch, timestepMinutes, PARAMETERS);
}
}
diff --git a/bundles/org.openhab.binding.fmiweather/src/main/java/org/openhab/binding/fmiweather/internal/config/ForecastConfiguration.java b/bundles/org.openhab.binding.fmiweather/src/main/java/org/openhab/binding/fmiweather/internal/config/ForecastConfiguration.java
new file mode 100644
index 00000000000..5ee66c87cc3
--- /dev/null
+++ b/bundles/org.openhab.binding.fmiweather/src/main/java/org/openhab/binding/fmiweather/internal/config/ForecastConfiguration.java
@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) 2010-2024 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.fmiweather.internal.config;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * The {@link ForecastConfiguration} class contains fields mapping Thing configuration parameters.
+ *
+ * @author Jacob Laursen - Initial contribution
+ */
+@NonNullByDefault
+public class ForecastConfiguration {
+ public static final String QUERY_HARMONIE = "harmonie";
+ public static final String QUERY_EDITED = "edited";
+
+ public String location = "";
+ public String query = QUERY_HARMONIE;
+}
diff --git a/bundles/org.openhab.binding.fmiweather/src/main/resources/OH-INF/i18n/fmiweather.properties b/bundles/org.openhab.binding.fmiweather/src/main/resources/OH-INF/i18n/fmiweather.properties
index f231e99d1a8..b6660125775 100644
--- a/bundles/org.openhab.binding.fmiweather/src/main/resources/OH-INF/i18n/fmiweather.properties
+++ b/bundles/org.openhab.binding.fmiweather/src/main/resources/OH-INF/i18n/fmiweather.properties
@@ -118,6 +118,10 @@ thing-type.fmiweather.observation.description = Finnish Meteorological Institute
thing-type.config.fmiweather.forecast.location.label = Location
thing-type.config.fmiweather.forecast.location.description = Location of weather in geographical coordinates (latitude,longitude).
+thing-type.config.fmiweather.forecast.query.label = Stored Query
+thing-type.config.fmiweather.forecast.query.description = Stored query for official FMI forecast
+thing-type.config.fmiweather.forecast.query.option.harmonie = Harmonie Surface Point Weather Forecast
+thing-type.config.fmiweather.forecast.query.option.edited = Forecast for Scandinavia (edited by a forecaster)
thing-type.config.fmiweather.observation.fmisid.label = FMISID of the Weather Station
thing-type.config.fmiweather.observation.fmisid.description = Station ID (FMISID) of the weather observation station
See https://en.ilmatieteenlaitos.fi/observation-stations for a list of observation stations. Select 'Weather' station for widest set of observations.
diff --git a/bundles/org.openhab.binding.fmiweather/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.fmiweather/src/main/resources/OH-INF/thing/thing-types.xml
index 7ce3e14f82b..468afc12d54 100644
--- a/bundles/org.openhab.binding.fmiweather/src/main/resources/OH-INF/thing/thing-types.xml
+++ b/bundles/org.openhab.binding.fmiweather/src/main/resources/OH-INF/thing/thing-types.xml
@@ -247,6 +247,15 @@
Location of weather in geographical coordinates (latitude,longitude).
+
+
+ Stored query for official FMI forecast
+ harmonie
+
+
+
+
+
diff --git a/bundles/org.openhab.binding.fmiweather/src/test/java/org/openhab/binding/fmiweather/FMIRequestTest.java b/bundles/org.openhab.binding.fmiweather/src/test/java/org/openhab/binding/fmiweather/FMIRequestTest.java
index 4bbd9a13a08..c4d6f3fc947 100644
--- a/bundles/org.openhab.binding.fmiweather/src/test/java/org/openhab/binding/fmiweather/FMIRequestTest.java
+++ b/bundles/org.openhab.binding.fmiweather/src/test/java/org/openhab/binding/fmiweather/FMIRequestTest.java
@@ -49,9 +49,9 @@ public class FMIRequestTest {
}
@Test
- public void testForecastRequestToUrl() {
- ForecastRequest request = new ForecastRequest(new LatLon(new BigDecimal("9"), new BigDecimal("8")), 1552215664L,
- 1552215665L, 61);
+ public void testForecastRequestToUrlHarmonie() {
+ ForecastRequest request = new ForecastRequest(new LatLon(new BigDecimal("9"), new BigDecimal("8")), "harmonie",
+ 1552215664L, 1552215665L, 61);
assertThat(request.toUrl(),
is("""
https://opendata.fmi.fi/wfs?service=WFS&version=2.0.0&request=getFeature&storedquery_id=fmi::forecast::harmonie::surface::point::multipointcoverage\
@@ -60,6 +60,18 @@ public class FMIRequestTest {
"""));
}
+ @Test
+ public void testForecastRequestToUrlEdited() {
+ ForecastRequest request = new ForecastRequest(new LatLon(new BigDecimal("9"), new BigDecimal("8")), "edited",
+ 1552215664L, 1552215665L, 61);
+ assertThat(request.toUrl(),
+ is("""
+ https://opendata.fmi.fi/wfs?service=WFS&version=2.0.0&request=getFeature&storedquery_id=fmi::forecast::edited::weather::scandinavia::point::multipointcoverage\
+ &starttime=2019-03-10T11:01:04Z&endtime=2019-03-10T11:01:05Z×tep=61&latlon=9,8\
+ ¶meters=Temperature,Humidity,WindDirection,WindSpeedMS,WindGust,Pressure,Precipitation1h,TotalCloudCover,WeatherSymbol3\
+ """));
+ }
+
@Test
public void testCustomLocation() {
QueryParameter location = new QueryParameter() {