diff --git a/bundles/org.openhab.binding.meteofrance/README.md b/bundles/org.openhab.binding.meteofrance/README.md index 6abad3ad289..993db9bfc7e 100644 --- a/bundles/org.openhab.binding.meteofrance/README.md +++ b/bundles/org.openhab.binding.meteofrance/README.md @@ -41,7 +41,7 @@ The `rain-forecast` thing has this configuration parameters: |-----------|--------------------------------------------------------------| | location | Geo coordinates to be considered by the service. | -## Channels +## Channels for `vigilance` The information that are retrieved is available as these channels: @@ -78,6 +78,24 @@ The information that are retrieved is available as these channels: | 2 | Orange | Be "very vigilant" in the concerned areas | | 3 | Red | Absolute vigilance required | +## Channels for `rain-forecast` + +The information that are retrieved is available as these channels: + +| Channel ID | Item Type | Description | +|--------------|-----------|--------------------------| +| update-time | DateTime | Observation Timestamp | +| intensity | Number | Rain intensity level (*) | + +(*) Rain intensity values and associated descriptions: + +| Code | Description | +|------|---------------| +| 0 | Dry Weather | +| 1 | Light Rain | +| 2 | Moderate Rain | +| 3 | Heavy Rain | + ## Provided icon set This binding has its own IconProvider and makes available the following list of icons @@ -101,7 +119,10 @@ This binding has its own IconProvider and makes available the following list of meteoalert.things: ```java -Thing meteofrance:department:yvelines @ "MyCity" [department="78", refresh=12] +Bridge meteofrance:api:local "Portail Météo-France" [ apikey="ey......FIjG1MIC9lmG5t6HygPAPg=="] { + vigilance yvelines "Vigilance Météo" [ department="78" ] + rain-forecast yvelines [ location="48.764207,2.05948" ] +} ``` meteoalert.items: @@ -129,4 +150,17 @@ Image MA_icon_avalanche "Avalanche" (gMeteoAlert) {channel="meteofrance:department:yvelines:observation-time"} +Number Intensite_Pluie "Intensité Pluie" (gMeteoAlert) {channel="meteofrance:rain-forecast:yvelines:intensity" } +``` + +jdbc.persist: + +```java + +Items { + * : strategy = everyChange + Intensite_Pluie : strategy = forecast +} + + ``` diff --git a/bundles/org.openhab.binding.meteofrance/src/main/java/org/openhab/binding/meteofrance/internal/db/DepartmentDbService.java b/bundles/org.openhab.binding.meteofrance/src/main/java/org/openhab/binding/meteofrance/internal/db/DepartmentDbService.java index 62aee3170aa..a818c73d960 100644 --- a/bundles/org.openhab.binding.meteofrance/src/main/java/org/openhab/binding/meteofrance/internal/db/DepartmentDbService.java +++ b/bundles/org.openhab.binding.meteofrance/src/main/java/org/openhab/binding/meteofrance/internal/db/DepartmentDbService.java @@ -22,7 +22,6 @@ import java.util.Arrays; import java.util.List; import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; import org.openhab.core.library.types.PointType; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; @@ -49,6 +48,11 @@ public class DepartmentDbService { public record Department(String id, String name, double northestLat, double southestLat, double eastestLon, double westestLon) { + + boolean contains(double latitude, double longitude) { + return northestLat >= latitude && southestLat <= latitude && // + westestLon <= longitude && eastestLon >= longitude; + } } @Activate @@ -58,7 +62,7 @@ public class DepartmentDbService { Reader reader = new InputStreamReader(is, StandardCharsets.UTF_8)) { Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create(); departments.addAll(Arrays.asList(gson.fromJson(reader, Department[].class))); - logger.debug("Successfully loaded {} departments", departments.size()); + logger.debug("Successfully loaded {} French departments", departments.size()); } catch (IOException | JsonSyntaxException | JsonIOException e) { logger.warn("Unable to load departments list: {}", e.getMessage()); } @@ -67,11 +71,6 @@ public class DepartmentDbService { public List getBounding(PointType location) { double latitude = location.getLatitude().doubleValue(); double longitude = location.getLongitude().doubleValue(); - return departments.stream().filter(dep -> dep.northestLat >= latitude && dep.southestLat <= latitude - && dep.westestLon <= longitude && dep.eastestLon >= longitude).toList(); - } - - public @Nullable Department getDept(String deptId) { - return departments.stream().filter(dep -> dep.id.equalsIgnoreCase(deptId)).findFirst().orElse(null); + return departments.stream().filter(dep -> dep.contains(latitude, longitude)).toList(); } } diff --git a/bundles/org.openhab.binding.meteofrance/src/main/java/org/openhab/binding/meteofrance/internal/dto/MeteoFrance.java b/bundles/org.openhab.binding.meteofrance/src/main/java/org/openhab/binding/meteofrance/internal/dto/MeteoFrance.java index 12ff8839d43..a29df45a327 100644 --- a/bundles/org.openhab.binding.meteofrance/src/main/java/org/openhab/binding/meteofrance/internal/dto/MeteoFrance.java +++ b/bundles/org.openhab.binding.meteofrance/src/main/java/org/openhab/binding/meteofrance/internal/dto/MeteoFrance.java @@ -55,8 +55,8 @@ public class MeteoFrance { Periods periods) { // périodes concernées par la Vigilance public Optional getBlocItem(Domain searched) { - return textBlocItems != null ? textBlocItems.stream().filter(ti -> ti.validFor(searched)).findFirst() - : Optional.empty(); + List local = textBlocItems; + return local != null ? local.stream().filter(ti -> ti.validFor(searched)).findFirst() : Optional.empty(); } public Optional getPeriod(Term term) { diff --git a/bundles/org.openhab.binding.meteofrance/src/main/java/org/openhab/binding/meteofrance/internal/handler/MeteoFranceBridgeHandler.java b/bundles/org.openhab.binding.meteofrance/src/main/java/org/openhab/binding/meteofrance/internal/handler/MeteoFranceBridgeHandler.java index e20abe75abd..070997d1f55 100644 --- a/bundles/org.openhab.binding.meteofrance/src/main/java/org/openhab/binding/meteofrance/internal/handler/MeteoFranceBridgeHandler.java +++ b/bundles/org.openhab.binding.meteofrance/src/main/java/org/openhab/binding/meteofrance/internal/handler/MeteoFranceBridgeHandler.java @@ -15,6 +15,7 @@ package org.openhab.binding.meteofrance.internal.handler; import static org.openhab.binding.meteofrance.internal.MeteoFranceBindingConstants.REQUEST_TIMEOUT_MS; import java.io.IOException; +import java.util.Locale; import java.util.Optional; import java.util.Properties; import java.util.concurrent.TimeUnit; @@ -159,10 +160,13 @@ public class MeteoFranceBridgeHandler extends BaseBridgeHandler { } public @Nullable RainForecast getRainForecast(PointType location) { - String url = RAIN_FORECAST_BASE_URL.formatted(location.getLatitude().doubleValue(), + String url = String.format(Locale.US, RAIN_FORECAST_BASE_URL, location.getLatitude().doubleValue(), location.getLongitude().doubleValue()); try { + logger.debug("Sending rain-forecast request to: {}", url); String answer = HttpUtil.executeUrl(HttpMethod.GET, url, REQUEST_TIMEOUT_MS); + logger.debug("Received answer: {}", answer); + return deserializer.deserialize(RainForecast.class, answer); } catch (MeteoFranceException e) { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, diff --git a/bundles/org.openhab.binding.meteofrance/src/main/java/org/openhab/binding/meteofrance/internal/handler/RainForecastHandler.java b/bundles/org.openhab.binding.meteofrance/src/main/java/org/openhab/binding/meteofrance/internal/handler/RainForecastHandler.java index a1e2d07ea89..c802c8dcd2f 100644 --- a/bundles/org.openhab.binding.meteofrance/src/main/java/org/openhab/binding/meteofrance/internal/handler/RainForecastHandler.java +++ b/bundles/org.openhab.binding.meteofrance/src/main/java/org/openhab/binding/meteofrance/internal/handler/RainForecastHandler.java @@ -116,9 +116,9 @@ public class RainForecastHandler extends BaseThingHandler implements MeteoFrance location.ifPresent(loc -> { RainForecast forecast = handler.getRainForecast(loc); if (forecast != null) { + updateStatus(ThingStatus.ONLINE); setProperties(forecast.properties); updateDate(UPDATE_TIME, forecast.updateTime); - updateStatus(ThingStatus.ONLINE); } }); }, () -> logger.warn("No viable bridge")); @@ -142,19 +142,29 @@ public class RainForecastHandler extends BaseThingHandler implements MeteoFrance private void setForecast(List forecast) { TimeSeries timeSeries = new TimeSeries(REPLACE); + ZonedDateTime now = ZonedDateTime.now(); - forecast.forEach(prevision -> { + State currentState = null; + long untilNextRun = 0; + for (Forecast prevision : forecast) { State state = prevision.rainIntensity() != RainIntensity.UNKNOWN ? new DecimalType(prevision.rainIntensity().ordinal()) : UnDefType.UNDEF; + if (currentState == null) { + currentState = state; + if (prevision.time().isAfter(now)) { + untilNextRun = now.until(prevision.time(), ChronoUnit.SECONDS); + } + } timeSeries.add(prevision.time().toInstant(), state); - }); + } + updateState(intensityChannelUID, currentState == null ? UnDefType.UNDEF : currentState); sendTimeSeries(intensityChannelUID, timeSeries); - Forecast current = forecast.get(0); - long until = ZonedDateTime.now().until(current.time(), ChronoUnit.SECONDS); - logger.debug("Refresh rain intensity forecast in : {}s", until); - refreshJob = Optional.of(scheduler.schedule(this::updateAndPublish, until, TimeUnit.SECONDS)); + untilNextRun = untilNextRun != 0 ? untilNextRun : 300; + + logger.debug("Refresh rain intensity forecast in: {}s", untilNextRun); + refreshJob = Optional.of(scheduler.schedule(this::updateAndPublish, untilNextRun, TimeUnit.SECONDS)); } private void updateDate(String channelId, @Nullable ZonedDateTime zonedDateTime) {