| observation-time | DateTime | Date and time of report validity start |
| end-time | DateTime | Date and time of report validity end |
| comment | String | General comments on alerts for the department |
-| vent | String | Wind alert level (*) |
-| pluie-inondation | String | Rain alert level (*) |
-| orage | String | Storm alert level (*) |
-| inondation | String | Flood alert level (*) |
-| neige | String | Snow alert level (*) |
-| canicule | String | Heat alert level (*) |
-| grand-froid | String | Cold alert level (*) |
-| avalanches | String | Avalanche alert level (*) |
-| vague-submersion | String | Wave submersion alert level (*) |
+| vent | Number | Wind alert level (*) |
+| pluie-inondation | Number | Rain alert level (*) |
+| orage | Number | Storm alert level (*) |
+| inondation | Number | Flood alert level (*) |
+| neige | Number | Snow alert level (*) |
+| canicule | Number | Heat alert level (*) |
+| grand-froid | Number | Cold alert level (*) |
+| avalanches | Number | Avalanche alert level (*) |
+| vague-submersion | Number | Wave submersion alert level (*) |
| pluie-inondation-icon | Image | Pictogram of the Rain alert level |
| vent-icon | Image | Pictogram of the Wind alert level |
| orage-icon | Image | Pictogram of Storm alert level |
```
Group gMeteoAlert "Alertes Météo" <weather>
String MA_Dept78 "Département 78 [%s]" <aqi> (gMeteoAlert) {channel="meteoalerte:department:yvelines:comment"}
- String MA_etat_canicule "Canicule [%s]" <aqi> (gMeteoAlert) {channel="meteoalerte:department:yvelines:canicule"}
- String MA_etat_grand_froid "Grand Froid [%s]" <aqi> (gMeteoAlert) {channel="meteoalerte:department:yvelines:grand-froid"}
- String MA_etat_pluie_inondation "Pluie-Inondation [%s]" <aqi> (gMeteoAlert) {channel="meteoalerte:department:yvelines:pluie-inondation"}
- String MA_etat_neige "Neige [%s]" <aqi> (gMeteoAlert) {channel="meteoalerte:department:yvelines:neige"}
- String MA_etat_vent "Vent [%s]" <aqi> (gMeteoAlert) {channel="meteoalerte:department:yvelines:vent"}
- String MA_etat_inondation "Inondation [%s]" <aqi> (gMeteoAlert) {channel="meteoalerte:department:yvelines:inondation"}
- String MA_etat_orage "Orage [%s]" <aqi> (gMeteoAlert) {channel="meteoalerte:department:yvelines:orage"}
- String MA_etat_avalanche "Avalanches [%s]" <aqi> (gMeteoAlert) {channel="meteoalerte:department:yvelines:avalanches"}
+ Number MA_etat_canicule "Canicule [%s]" <aqi> (gMeteoAlert) {channel="meteoalerte:department:yvelines:canicule"}
+ Number MA_etat_grand_froid "Grand Froid [%s]" <aqi> (gMeteoAlert) {channel="meteoalerte:department:yvelines:grand-froid"}
+ Number MA_etat_pluie_inondation "Pluie-Inondation [%s]" <aqi> (gMeteoAlert) {channel="meteoalerte:department:yvelines:pluie-inondation"}
+ Number MA_etat_neige "Neige [%s]" <aqi> (gMeteoAlert) {channel="meteoalerte:department:yvelines:neige"}
+ Number MA_etat_vent "Vent [%s]" <aqi> (gMeteoAlert) {channel="meteoalerte:department:yvelines:vent"}
+ Number MA_etat_inondation "Inondation [%s]" <aqi> (gMeteoAlert) {channel="meteoalerte:department:yvelines:inondation"}
+ Number MA_etat_orage "Orage [%s]" <aqi> (gMeteoAlert) {channel="meteoalerte:department:yvelines:orage"}
+ Number MA_etat_avalanche "Avalanches [%s]" <aqi> (gMeteoAlert) {channel="meteoalerte:department:yvelines:avalanches"}
Image MA_icon_canicule "Canicule" <aqi> (gMeteoAlert) {channel="meteoalerte:department:yvelines:canicule-icon"}
Image MA_icon_grand_froid "Grand Froid" <aqi> (gMeteoAlert) {channel="meteoalerte:department:yvelines:grand-froid-icon"}
import static org.openhab.binding.meteoalerte.internal.MeteoAlerteBindingConstants.*;
-import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
-import java.io.InputStreamReader;
import java.net.MalformedURLException;
+import java.nio.charset.StandardCharsets;
import java.time.ZonedDateTime;
import java.util.AbstractMap;
-import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.meteoalerte.internal.json.ResponseFieldDTO.AlertLevel;
import org.openhab.core.io.net.http.HttpUtil;
import org.openhab.core.library.types.DateTimeType;
+import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.RawType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
+import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.FrameworkUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MeteoAlerteHandler extends BaseThingHandler {
private static final String URL = "https://public.opendatasoft.com/api/records/1.0/search/?dataset=risques-meteorologiques-copy&"
+ "facet=etat_vent&facet=etat_pluie_inondation&facet=etat_orage&facet=etat_inondation&facet=etat_neige&facet=etat_canicule&"
- + "facet=etat_grand_froid&facet=etat_avalanches&refine.nom_dept=";
+ + "facet=etat_grand_froid&facet=etat_avalanches&refine.nom_dept=%s";
private static final int TIMEOUT_MS = 30000;
private static final String UNKNOWN_COLOR = "b3b3b3";
private static final Map<AlertLevel, String> ALERT_COLORS = Map.ofEntries(
logger.debug("config refresh = {}", config.refresh);
updateStatus(ThingStatus.UNKNOWN);
- queryUrl = URL + config.department;
+ queryUrl = String.format(URL, config.department);
refreshJob = scheduler.scheduleWithFixedDelay(this::updateAndPublish, 0, config.refresh, TimeUnit.MINUTES);
}
* @param channelId the id identifying the channel to be updated
*/
private void updateChannels(ApiResponse apiResponse) {
- Arrays.stream(apiResponse.getRecords()).findFirst()
- .ifPresent((record) -> record.getResponseFieldDTO().ifPresent(fields -> {
- updateAlert(WIND, fields.getVent());
- updateAlert(RAIN, fields.getPluieInondation());
- updateAlert(STORM, fields.getOrage());
- updateAlert(FLOOD, fields.getInondation());
- updateAlert(SNOW, fields.getNeige());
- updateAlert(HEAT, fields.getCanicule());
- updateAlert(FREEZE, fields.getGrandFroid());
- updateAlert(AVALANCHE, fields.getAvalanches());
- updateAlert(WAVE, fields.getVagueSubmersion());
- updateState(COMMENT, new StringType(fields.getVigilanceComment()));
- fields.getDateInsert().ifPresent(date -> updateDate(OBSERVATION_TIME, date));
- fields.getDatePrevue().ifPresent(date -> updateDate(END_TIME, date));
- }));
+ apiResponse.getRecords().findFirst().ifPresent((record) -> record.getResponseFieldDTO().ifPresent(fields -> {
+ updateAlert(WIND, fields.getVent());
+ updateAlert(RAIN, fields.getPluieInondation());
+ updateAlert(STORM, fields.getOrage());
+ updateAlert(FLOOD, fields.getInondation());
+ updateAlert(SNOW, fields.getNeige());
+ updateAlert(HEAT, fields.getCanicule());
+ updateAlert(FREEZE, fields.getGrandFroid());
+ updateAlert(AVALANCHE, fields.getAvalanches());
+ updateAlert(WAVE, fields.getVagueSubmersion());
+ updateState(COMMENT, new StringType(fields.getVigilanceComment()));
+ fields.getDateInsert().ifPresent(date -> updateDate(OBSERVATION_TIME, date));
+ fields.getDatePrevue().ifPresent(date -> updateDate(END_TIME, date));
+ }));
}
- public @Nullable String getResource(String iconPath) {
- Bundle bundle = FrameworkUtil.getBundle(getClass());
- try (InputStream stream = bundle.getResource(iconPath).openStream()) {
- return new BufferedReader(new InputStreamReader(stream)).lines().collect(Collectors.joining("\n"));
- } catch (IOException e) {
- logger.warn("Unable to load ressource '{}' : {}", iconPath, e.getMessage());
+ public byte @Nullable [] getResource(String iconPath) {
+ ClassLoader classLoader = MeteoAlerteHandler.class.getClassLoader();
+ if (classLoader != null) {
+ try (InputStream stream = classLoader.getResourceAsStream(iconPath)) {
+ return stream != null ? stream.readAllBytes() : null;
+ } catch (IOException e) {
+ logger.warn("Unable to load ressource '{}' : {}", iconPath, e.getMessage());
+ }
}
return null;
}
public void updateAlert(String channelId, AlertLevel value) {
String channelIcon = channelId + "-icon";
if (isLinked(channelId)) {
- updateState(channelId, value != AlertLevel.UNKNOWN ? new StringType(value.name()) : UnDefType.UNDEF);
+ updateState(channelId, getAlertLevel(value));
}
if (isLinked(channelIcon)) {
- String resource = getResource(String.format("picto/%s.svg", channelId));
- if (resource != null) {
+ State result = UnDefType.UNDEF;
+ byte[] bytes = getResource(String.format("picto/%s.svg", channelId));
+ if (bytes != null) {
+ String resource = new String(bytes, StandardCharsets.UTF_8);
resource = resource.replaceAll(UNKNOWN_COLOR, ALERT_COLORS.getOrDefault(value, UNKNOWN_COLOR));
+ result = new RawType(resource.getBytes(StandardCharsets.UTF_8), "image/svg+xml");
}
- updateState(channelIcon,
- resource != null ? new RawType(resource.getBytes(), "image/svg+xml") : UnDefType.UNDEF);
+ updateState(channelIcon, result);
}
}
updateState(channelId, new DateTimeType(zonedDateTime));
}
}
+
+ public State getAlertLevel(AlertLevel alert) {
+ switch (alert) {
+ case GREEN:
+ return DecimalType.ZERO;
+ case YELLOW:
+ return new DecimalType(1);
+ case ORANGE:
+ return new DecimalType(2);
+ case RED:
+ return new DecimalType(3);
+ default:
+ return UnDefType.UNDEF;
+ }
+ }
}