mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[meteofrance] Documentation enhancements and more (#17740)
* Some binding enhancements Signed-off-by: Gaël L'hopital <gael@lhopital.org>
This commit is contained in:
parent
b4fb5a1f1b
commit
91f16fa16c
@ -41,7 +41,7 @@ The `rain-forecast` thing has this configuration parameters:
|
|||||||
|-----------|--------------------------------------------------------------|
|
|-----------|--------------------------------------------------------------|
|
||||||
| location | Geo coordinates to be considered by the service. |
|
| location | Geo coordinates to be considered by the service. |
|
||||||
|
|
||||||
## Channels
|
## Channels for `vigilance`
|
||||||
|
|
||||||
The information that are retrieved is available as these channels:
|
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 |
|
| 2 | Orange | Be "very vigilant" in the concerned areas |
|
||||||
| 3 | Red | Absolute vigilance required |
|
| 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
|
## Provided icon set
|
||||||
|
|
||||||
This binding has its own IconProvider and makes available the following list of icons
|
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:
|
meteoalert.things:
|
||||||
|
|
||||||
```java
|
```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:
|
meteoalert.items:
|
||||||
@ -129,4 +150,17 @@ Image MA_icon_avalanche "Avalanche" <oh:meteofranc
|
|||||||
|
|
||||||
DateTime MA_ObservationTS "Timestamp [%1$tH:%1$tM]" <time> (gMeteoAlert) {channel="meteofrance:department:yvelines:observation-time"}
|
DateTime MA_ObservationTS "Timestamp [%1$tH:%1$tM]" <time> (gMeteoAlert) {channel="meteofrance:department:yvelines:observation-time"}
|
||||||
|
|
||||||
|
Number Intensite_Pluie "Intensité Pluie" <oh:meteofrance:intensity> (gMeteoAlert) {channel="meteofrance:rain-forecast:yvelines:intensity" }
|
||||||
|
```
|
||||||
|
|
||||||
|
jdbc.persist:
|
||||||
|
|
||||||
|
```java
|
||||||
|
|
||||||
|
Items {
|
||||||
|
* : strategy = everyChange
|
||||||
|
Intensite_Pluie : strategy = forecast
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -22,7 +22,6 @@ import java.util.Arrays;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
|
||||||
import org.openhab.core.library.types.PointType;
|
import org.openhab.core.library.types.PointType;
|
||||||
import org.osgi.service.component.annotations.Activate;
|
import org.osgi.service.component.annotations.Activate;
|
||||||
import org.osgi.service.component.annotations.Component;
|
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,
|
public record Department(String id, String name, double northestLat, double southestLat, double eastestLon,
|
||||||
double westestLon) {
|
double westestLon) {
|
||||||
|
|
||||||
|
boolean contains(double latitude, double longitude) {
|
||||||
|
return northestLat >= latitude && southestLat <= latitude && //
|
||||||
|
westestLon <= longitude && eastestLon >= longitude;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Activate
|
@Activate
|
||||||
@ -58,7 +62,7 @@ public class DepartmentDbService {
|
|||||||
Reader reader = new InputStreamReader(is, StandardCharsets.UTF_8)) {
|
Reader reader = new InputStreamReader(is, StandardCharsets.UTF_8)) {
|
||||||
Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
|
Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
|
||||||
departments.addAll(Arrays.asList(gson.fromJson(reader, Department[].class)));
|
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) {
|
} catch (IOException | JsonSyntaxException | JsonIOException e) {
|
||||||
logger.warn("Unable to load departments list: {}", e.getMessage());
|
logger.warn("Unable to load departments list: {}", e.getMessage());
|
||||||
}
|
}
|
||||||
@ -67,11 +71,6 @@ public class DepartmentDbService {
|
|||||||
public List<Department> getBounding(PointType location) {
|
public List<Department> getBounding(PointType location) {
|
||||||
double latitude = location.getLatitude().doubleValue();
|
double latitude = location.getLatitude().doubleValue();
|
||||||
double longitude = location.getLongitude().doubleValue();
|
double longitude = location.getLongitude().doubleValue();
|
||||||
return departments.stream().filter(dep -> dep.northestLat >= latitude && dep.southestLat <= latitude
|
return departments.stream().filter(dep -> dep.contains(latitude, longitude)).toList();
|
||||||
&& 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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,8 +55,8 @@ public class MeteoFrance {
|
|||||||
Periods periods) { // périodes concernées par la Vigilance
|
Periods periods) { // périodes concernées par la Vigilance
|
||||||
|
|
||||||
public Optional<TextBlocItem> getBlocItem(Domain searched) {
|
public Optional<TextBlocItem> getBlocItem(Domain searched) {
|
||||||
return textBlocItems != null ? textBlocItems.stream().filter(ti -> ti.validFor(searched)).findFirst()
|
List<TextBlocItem> local = textBlocItems;
|
||||||
: Optional.empty();
|
return local != null ? local.stream().filter(ti -> ti.validFor(searched)).findFirst() : Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<Period> getPeriod(Term term) {
|
public Optional<Period> getPeriod(Term term) {
|
||||||
|
@ -15,6 +15,7 @@ package org.openhab.binding.meteofrance.internal.handler;
|
|||||||
import static org.openhab.binding.meteofrance.internal.MeteoFranceBindingConstants.REQUEST_TIMEOUT_MS;
|
import static org.openhab.binding.meteofrance.internal.MeteoFranceBindingConstants.REQUEST_TIMEOUT_MS;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@ -159,10 +160,13 @@ public class MeteoFranceBridgeHandler extends BaseBridgeHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable RainForecast getRainForecast(PointType location) {
|
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());
|
location.getLongitude().doubleValue());
|
||||||
try {
|
try {
|
||||||
|
logger.debug("Sending rain-forecast request to: {}", url);
|
||||||
String answer = HttpUtil.executeUrl(HttpMethod.GET, url, REQUEST_TIMEOUT_MS);
|
String answer = HttpUtil.executeUrl(HttpMethod.GET, url, REQUEST_TIMEOUT_MS);
|
||||||
|
logger.debug("Received answer: {}", answer);
|
||||||
|
|
||||||
return deserializer.deserialize(RainForecast.class, answer);
|
return deserializer.deserialize(RainForecast.class, answer);
|
||||||
} catch (MeteoFranceException e) {
|
} catch (MeteoFranceException e) {
|
||||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||||
|
@ -116,9 +116,9 @@ public class RainForecastHandler extends BaseThingHandler implements MeteoFrance
|
|||||||
location.ifPresent(loc -> {
|
location.ifPresent(loc -> {
|
||||||
RainForecast forecast = handler.getRainForecast(loc);
|
RainForecast forecast = handler.getRainForecast(loc);
|
||||||
if (forecast != null) {
|
if (forecast != null) {
|
||||||
|
updateStatus(ThingStatus.ONLINE);
|
||||||
setProperties(forecast.properties);
|
setProperties(forecast.properties);
|
||||||
updateDate(UPDATE_TIME, forecast.updateTime);
|
updateDate(UPDATE_TIME, forecast.updateTime);
|
||||||
updateStatus(ThingStatus.ONLINE);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, () -> logger.warn("No viable bridge"));
|
}, () -> logger.warn("No viable bridge"));
|
||||||
@ -142,19 +142,29 @@ public class RainForecastHandler extends BaseThingHandler implements MeteoFrance
|
|||||||
|
|
||||||
private void setForecast(List<Forecast> forecast) {
|
private void setForecast(List<Forecast> forecast) {
|
||||||
TimeSeries timeSeries = new TimeSeries(REPLACE);
|
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
|
State state = prevision.rainIntensity() != RainIntensity.UNKNOWN
|
||||||
? new DecimalType(prevision.rainIntensity().ordinal())
|
? new DecimalType(prevision.rainIntensity().ordinal())
|
||||||
: UnDefType.UNDEF;
|
: 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);
|
timeSeries.add(prevision.time().toInstant(), state);
|
||||||
});
|
}
|
||||||
|
updateState(intensityChannelUID, currentState == null ? UnDefType.UNDEF : currentState);
|
||||||
sendTimeSeries(intensityChannelUID, timeSeries);
|
sendTimeSeries(intensityChannelUID, timeSeries);
|
||||||
|
|
||||||
Forecast current = forecast.get(0);
|
untilNextRun = untilNextRun != 0 ? untilNextRun : 300;
|
||||||
long until = ZonedDateTime.now().until(current.time(), ChronoUnit.SECONDS);
|
|
||||||
logger.debug("Refresh rain intensity forecast in : {}s", until);
|
logger.debug("Refresh rain intensity forecast in: {}s", untilNextRun);
|
||||||
refreshJob = Optional.of(scheduler.schedule(this::updateAndPublish, until, TimeUnit.SECONDS));
|
refreshJob = Optional.of(scheduler.schedule(this::updateAndPublish, untilNextRun, TimeUnit.SECONDS));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateDate(String channelId, @Nullable ZonedDateTime zonedDateTime) {
|
private void updateDate(String channelId, @Nullable ZonedDateTime zonedDateTime) {
|
||||||
|
Loading…
Reference in New Issue
Block a user