[meteoalerte] Addressing Issue #8543 (#8961)

* [meteoalerte] Addressing Issue #8543

* Small change
* Adding charset to byte conversion

Signed-off-by: clinique <gael@lhopital.org>
This commit is contained in:
Gaël L'hopital 2020-11-09 21:51:39 +01:00 committed by GitHub
parent 4579fae00a
commit afe711994a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 77 additions and 59 deletions

View File

@ -30,15 +30,15 @@ The Météo Alerte information that are retrieved is available as these channels
| 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 |
@ -72,14 +72,14 @@ meteoalert.items:
```
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"}

View File

@ -14,18 +14,15 @@ package org.openhab.binding.meteoalerte.internal.handler;
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;
@ -34,6 +31,7 @@ import org.openhab.binding.meteoalerte.internal.json.ApiResponse;
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;
@ -43,9 +41,8 @@ import org.openhab.core.thing.ThingStatusDetail;
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;
@ -61,7 +58,7 @@ import com.google.gson.Gson;
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(
@ -91,7 +88,7 @@ public class MeteoAlerteHandler extends BaseThingHandler {
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);
}
@ -135,29 +132,30 @@ public class MeteoAlerteHandler extends BaseThingHandler {
* @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;
}
@ -165,15 +163,17 @@ public class MeteoAlerteHandler extends BaseThingHandler {
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);
}
}
@ -182,4 +182,19 @@ public class MeteoAlerteHandler extends BaseThingHandler {
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;
}
}
}

View File

@ -12,7 +12,10 @@
*/
package org.openhab.binding.meteoalerte.internal.json;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
@ -30,7 +33,7 @@ public class ApiResponse {
@SerializedName("nhits")
private int nHits;
private @Nullable Parameters parameters;
private Record[] records = {};
private List<Record> records = new ArrayList<>();
public int getNHits() {
return nHits;
@ -44,7 +47,7 @@ public class ApiResponse {
return Optional.empty();
}
public Record[] getRecords() {
return records;
public Stream<Record> getRecords() {
return records.stream();
}
}

View File

@ -185,14 +185,14 @@
</thing-type>
<channel-type id="alert-level">
<item-type>String</item-type>
<item-type>Number</item-type>
<label>Alerte</label>
<state readOnly="true">
<options>
<option value="GREEN">Vert</option>
<option value="YELLOW">Jaune</option>
<option value="ORANGE">Orange</option>
<option value="RED">Rouge</option>
<option value="0">Vert</option>
<option value="1">Jaune</option>
<option value="2">Orange</option>
<option value="3">Rouge</option>
</options>
</state>
</channel-type>