From 9aa3255adab59f6a769e4fd8666c852203901539 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20L=27hopital?= Date: Tue, 19 Nov 2024 12:22:41 +0100 Subject: [PATCH] Adding Air Quality index MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gaël L'hopital --- .../internal/AirParifBindingConstants.java | 1 + .../internal/AirParifHandlerFactory.java | 6 +-- .../internal/AirParifIconProvider.java | 33 +++++++------- .../airparif/internal/api/AirParifApi.java | 2 +- .../airparif/internal/api/AirParifDto.java | 28 ++++++++++++ .../airparif/internal/api/Pollutant.java | 43 +++++++++++++++---- .../handler/AirParifBridgeHandler.java | 22 ++-------- .../internal/handler/LocationHandler.java | 26 +++++++---- .../resources/OH-INF/i18n/airparif.properties | 41 ++++++++++++------ .../resources/OH-INF/thing/channel-groups.xml | 38 +++++----------- .../main/resources/OH-INF/thing/channels.xml | 22 +++++++--- .../resources/OH-INF/thing/thing-types.xml | 4 +- .../src/main/resources/icon/alder.svg | 0 .../src/main/resources/icon/aq-0.svg | 8 ++++ .../src/main/resources/icon/aq-1.svg | 7 +++ .../src/main/resources/icon/aq-2.svg | 7 +++ .../src/main/resources/icon/aq-3.svg | 9 ++++ .../src/main/resources/icon/aq-4.svg | 9 ++++ .../src/main/resources/icon/aq-5.svg | 6 +++ .../src/main/resources/icon/aq.svg | 7 +++ .../src/main/resources/icon/ash.svg | 0 .../src/main/resources/icon/average.svg | 7 --- .../src/main/resources/icon/bad.svg | 9 ---- .../src/main/resources/icon/birch.svg | 0 .../src/main/resources/icon/chestnut.svg | 0 .../src/main/resources/icon/cypress.svg | 0 .../src/main/resources/icon/degrated.svg | 7 --- .../src/main/resources/icon/extremely-bad.svg | 6 --- .../src/main/resources/icon/good.svg | 8 ---- .../src/main/resources/icon/grasses.svg | 0 .../src/main/resources/icon/hazel.svg | 0 .../src/main/resources/icon/hornbeam.svg | 0 .../src/main/resources/icon/linden.svg | 0 .../src/main/resources/icon/oak.svg | 0 .../src/main/resources/icon/olive.svg | 0 .../src/main/resources/icon/plane.svg | 0 .../src/main/resources/icon/plantain.svg | 0 .../src/main/resources/icon/pollen.svg | 0 .../src/main/resources/icon/poplar.svg | 0 .../src/main/resources/icon/ragweed.svg | 0 .../src/main/resources/icon/rumex.svg | 0 .../src/main/resources/icon/urticaceae.svg | 0 .../src/main/resources/icon/willow.svg | 0 .../src/main/resources/icon/wormwood.svg | 0 44 files changed, 216 insertions(+), 140 deletions(-) mode change 100644 => 100755 bundles/org.openhab.binding.airparif/src/main/resources/icon/alder.svg create mode 100755 bundles/org.openhab.binding.airparif/src/main/resources/icon/aq-0.svg create mode 100755 bundles/org.openhab.binding.airparif/src/main/resources/icon/aq-1.svg create mode 100755 bundles/org.openhab.binding.airparif/src/main/resources/icon/aq-2.svg create mode 100755 bundles/org.openhab.binding.airparif/src/main/resources/icon/aq-3.svg create mode 100755 bundles/org.openhab.binding.airparif/src/main/resources/icon/aq-4.svg create mode 100755 bundles/org.openhab.binding.airparif/src/main/resources/icon/aq-5.svg create mode 100755 bundles/org.openhab.binding.airparif/src/main/resources/icon/aq.svg mode change 100644 => 100755 bundles/org.openhab.binding.airparif/src/main/resources/icon/ash.svg delete mode 100644 bundles/org.openhab.binding.airparif/src/main/resources/icon/average.svg delete mode 100644 bundles/org.openhab.binding.airparif/src/main/resources/icon/bad.svg mode change 100644 => 100755 bundles/org.openhab.binding.airparif/src/main/resources/icon/birch.svg mode change 100644 => 100755 bundles/org.openhab.binding.airparif/src/main/resources/icon/chestnut.svg mode change 100644 => 100755 bundles/org.openhab.binding.airparif/src/main/resources/icon/cypress.svg delete mode 100644 bundles/org.openhab.binding.airparif/src/main/resources/icon/degrated.svg delete mode 100644 bundles/org.openhab.binding.airparif/src/main/resources/icon/extremely-bad.svg delete mode 100644 bundles/org.openhab.binding.airparif/src/main/resources/icon/good.svg mode change 100644 => 100755 bundles/org.openhab.binding.airparif/src/main/resources/icon/grasses.svg mode change 100644 => 100755 bundles/org.openhab.binding.airparif/src/main/resources/icon/hazel.svg mode change 100644 => 100755 bundles/org.openhab.binding.airparif/src/main/resources/icon/hornbeam.svg mode change 100644 => 100755 bundles/org.openhab.binding.airparif/src/main/resources/icon/linden.svg mode change 100644 => 100755 bundles/org.openhab.binding.airparif/src/main/resources/icon/oak.svg mode change 100644 => 100755 bundles/org.openhab.binding.airparif/src/main/resources/icon/olive.svg mode change 100644 => 100755 bundles/org.openhab.binding.airparif/src/main/resources/icon/plane.svg mode change 100644 => 100755 bundles/org.openhab.binding.airparif/src/main/resources/icon/plantain.svg mode change 100644 => 100755 bundles/org.openhab.binding.airparif/src/main/resources/icon/pollen.svg mode change 100644 => 100755 bundles/org.openhab.binding.airparif/src/main/resources/icon/poplar.svg mode change 100644 => 100755 bundles/org.openhab.binding.airparif/src/main/resources/icon/ragweed.svg mode change 100644 => 100755 bundles/org.openhab.binding.airparif/src/main/resources/icon/rumex.svg mode change 100644 => 100755 bundles/org.openhab.binding.airparif/src/main/resources/icon/urticaceae.svg mode change 100644 => 100755 bundles/org.openhab.binding.airparif/src/main/resources/icon/willow.svg mode change 100644 => 100755 bundles/org.openhab.binding.airparif/src/main/resources/icon/wormwood.svg diff --git a/bundles/org.openhab.binding.airparif/src/main/java/org/openhab/binding/airparif/internal/AirParifBindingConstants.java b/bundles/org.openhab.binding.airparif/src/main/java/org/openhab/binding/airparif/internal/AirParifBindingConstants.java index 8a9d22fbc2e..8b6e19c9fd1 100755 --- a/bundles/org.openhab.binding.airparif/src/main/java/org/openhab/binding/airparif/internal/AirParifBindingConstants.java +++ b/bundles/org.openhab.binding.airparif/src/main/java/org/openhab/binding/airparif/internal/AirParifBindingConstants.java @@ -47,6 +47,7 @@ public class AirParifBindingConstants { public static final String CHANNEL_TOMORROW = "tomorrow"; public static final String CHANNEL_TIMESTAMP = "timestamp"; public static final String CHANNEL_VALUE = "value"; + public static final String CHANNEL_ALERT = "alert"; public static final Set SUPPORTED_THING_TYPES_UIDS = Set.of(APIBRIDGE_THING_TYPE, LOCATION_THING_TYPE); diff --git a/bundles/org.openhab.binding.airparif/src/main/java/org/openhab/binding/airparif/internal/AirParifHandlerFactory.java b/bundles/org.openhab.binding.airparif/src/main/java/org/openhab/binding/airparif/internal/AirParifHandlerFactory.java index ac814ef3a5c..ea9f49da607 100755 --- a/bundles/org.openhab.binding.airparif/src/main/java/org/openhab/binding/airparif/internal/AirParifHandlerFactory.java +++ b/bundles/org.openhab.binding.airparif/src/main/java/org/openhab/binding/airparif/internal/AirParifHandlerFactory.java @@ -41,14 +41,12 @@ import org.osgi.service.component.annotations.Reference; public class AirParifHandlerFactory extends BaseThingHandlerFactory { private final AirParifDeserializer deserializer; private final HttpClient httpClient; - private final AirParifIconProvider iconProvider; @Activate public AirParifHandlerFactory(final @Reference HttpClientFactory httpClientFactory, - final @Reference AirParifDeserializer deserializer, final @Reference AirParifIconProvider iconProvider) { + final @Reference AirParifDeserializer deserializer) { this.httpClient = httpClientFactory.getCommonHttpClient(); this.deserializer = deserializer; - this.iconProvider = iconProvider; } @Override @@ -61,7 +59,7 @@ public class AirParifHandlerFactory extends BaseThingHandlerFactory { ThingTypeUID thingTypeUID = thing.getThingTypeUID(); return APIBRIDGE_THING_TYPE.equals(thingTypeUID) - ? new AirParifBridgeHandler((Bridge) thing, httpClient, deserializer, iconProvider) + ? new AirParifBridgeHandler((Bridge) thing, httpClient, deserializer) : LOCATION_THING_TYPE.equals(thingTypeUID) ? new LocationHandler(thing) : null; } } diff --git a/bundles/org.openhab.binding.airparif/src/main/java/org/openhab/binding/airparif/internal/AirParifIconProvider.java b/bundles/org.openhab.binding.airparif/src/main/java/org/openhab/binding/airparif/internal/AirParifIconProvider.java index d893d010df8..f95f4cdcf02 100755 --- a/bundles/org.openhab.binding.airparif/src/main/java/org/openhab/binding/airparif/internal/AirParifIconProvider.java +++ b/bundles/org.openhab.binding.airparif/src/main/java/org/openhab/binding/airparif/internal/AirParifIconProvider.java @@ -26,7 +26,6 @@ import java.util.Set; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.airparif.internal.api.AirParifApi.Pollen; -import org.openhab.binding.airparif.internal.api.ColorMap; import org.openhab.binding.airparif.internal.api.PollenAlertLevel; import org.openhab.core.i18n.TranslationProvider; import org.openhab.core.ui.icon.IconProvider; @@ -50,15 +49,14 @@ import org.slf4j.LoggerFactory; public class AirParifIconProvider implements IconProvider { private static final String NEUTRAL_COLOR = "#3d3c3c"; private static final String DEFAULT_LABEL = "Air Parif Icons"; + private static final String AQ_ICON = "aq"; private static final String DEFAULT_DESCRIPTION = "Icons illustrating air quality levels provided by AirParif"; - private static final List ICONS = List.of("average", "bad", "degrated", "extremely-bad", "good", "pollen"); private static final List POLLEN_ICONS = Pollen.AS_SET.stream().map(Pollen::name).map(String::toLowerCase) .toList(); private final Logger logger = LoggerFactory.getLogger(AirParifIconProvider.class); private final TranslationProvider i18nProvider; private final Bundle bundle; - private @Nullable ColorMap colorMap; @Activate public AirParifIconProvider(final BundleContext context, final @Reference TranslationProvider i18nProvider) { @@ -87,24 +85,31 @@ public class AirParifIconProvider implements IconProvider { @Override public @Nullable Integer hasIcon(String category, String iconSetId, Format format) { return Format.SVG.equals(format) && iconSetId.equals(BINDING_ID) - && (ICONS.contains(category) || POLLEN_ICONS.contains(category)) ? 0 : null; + && (category.equals(AQ_ICON) || POLLEN_ICONS.contains(category)) ? 0 : null; } @Override public @Nullable InputStream getIcon(String category, String iconSetId, @Nullable String state, Format format) { - URL iconResource = bundle.getEntry("icon/%s.svg".formatted(category)); + int ordinal = -1; + try { + ordinal = state != null ? Integer.valueOf(state) : -1; + } catch (NumberFormatException ignore) { + } + + String iconName = "icon/%s.svg".formatted(category); + if (category.equals(AQ_ICON) && ordinal != -1) { + iconName = iconName.replace(".", "-%d.".formatted(ordinal)); + } + + URL iconResource = bundle.getEntry(iconName); String result; try (InputStream stream = iconResource.openStream()) { result = new String(stream.readAllBytes(), StandardCharsets.UTF_8); - if (POLLEN_ICONS.contains(category) && state != null) { - try { - int ordinal = Integer.valueOf(state); - PollenAlertLevel alertLevel = PollenAlertLevel.valueOf(ordinal); - result = result.replaceAll(NEUTRAL_COLOR, alertLevel.color); - } catch (NumberFormatException ignore) { - } + if (POLLEN_ICONS.contains(category)) { + PollenAlertLevel alertLevel = PollenAlertLevel.valueOf(ordinal); + result = result.replaceAll(NEUTRAL_COLOR, alertLevel.color); } } catch (IOException e) { logger.warn("Unable to load ressource '{}': {}", iconResource.getPath(), e.getMessage()); @@ -113,8 +118,4 @@ public class AirParifIconProvider implements IconProvider { return result.isEmpty() ? null : new ByteArrayInputStream(result.getBytes()); } - - public void setColorMap(ColorMap map) { - this.colorMap = map; - } } diff --git a/bundles/org.openhab.binding.airparif/src/main/java/org/openhab/binding/airparif/internal/api/AirParifApi.java b/bundles/org.openhab.binding.airparif/src/main/java/org/openhab/binding/airparif/internal/api/AirParifApi.java index 95f387064b3..5349d18caef 100644 --- a/bundles/org.openhab.binding.airparif/src/main/java/org/openhab/binding/airparif/internal/api/AirParifApi.java +++ b/bundles/org.openhab.binding.airparif/src/main/java/org/openhab/binding/airparif/internal/api/AirParifApi.java @@ -62,7 +62,7 @@ public class AirParifApi { AVERAGE("Moyen"), DEGRATED("Dégradé"), BAD("Mauvais"), - REALLY_BAD("Très Mauvais"), + VERY_BAD("Très Mauvais"), EXTREMELY_BAD("Extrêmement Mauvais"), UNKNOWN(""); diff --git a/bundles/org.openhab.binding.airparif/src/main/java/org/openhab/binding/airparif/internal/api/AirParifDto.java b/bundles/org.openhab.binding.airparif/src/main/java/org/openhab/binding/airparif/internal/api/AirParifDto.java index 0dd508a2988..c13da7d22b6 100644 --- a/bundles/org.openhab.binding.airparif/src/main/java/org/openhab/binding/airparif/internal/api/AirParifDto.java +++ b/bundles/org.openhab.binding.airparif/src/main/java/org/openhab/binding/airparif/internal/api/AirParifDto.java @@ -27,10 +27,13 @@ import java.util.TreeSet; import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.measure.Unit; + import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.airparif.internal.api.AirParifApi.Pollen; import org.openhab.binding.airparif.internal.api.AirParifApi.Scope; +import org.openhab.core.library.types.QuantityType; import org.openhab.core.library.types.StringType; import org.openhab.core.types.State; import org.openhab.core.types.UnDefType; @@ -63,6 +66,22 @@ public class AirParifDto { Pollutant pollutant, // int min, // int max) { + + private State getQuantity(int value) { + Unit unit = pollutant.unit; + if (unit != null) { + return new QuantityType<>(value, unit); + } + return UnDefType.NULL; + } + + public State getMin() { + return getQuantity(min); + } + + public State getMax() { + return getQuantity(max); + } } public record PollutantEpisode(// @@ -185,9 +204,18 @@ public class AirParifDto { return message != null ? new StringType(message.fr()) : UnDefType.NULL; } + public State getQuantity() { + Unit unit = pollutant.unit; + return unit != null ? new QuantityType<>(getValue(), unit) : UnDefType.NULL; + } + public double getValue() { return values[0]; } + + public int getAlertLevel() { + return pollutant.getAppreciation(getValue()).ordinal(); + } } public record Route(// diff --git a/bundles/org.openhab.binding.airparif/src/main/java/org/openhab/binding/airparif/internal/api/Pollutant.java b/bundles/org.openhab.binding.airparif/src/main/java/org/openhab/binding/airparif/internal/api/Pollutant.java index 4298a621aad..bf21998970b 100644 --- a/bundles/org.openhab.binding.airparif/src/main/java/org/openhab/binding/airparif/internal/api/Pollutant.java +++ b/bundles/org.openhab.binding.airparif/src/main/java/org/openhab/binding/airparif/internal/api/Pollutant.java @@ -17,6 +17,8 @@ import java.util.EnumSet; import javax.measure.Unit; import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.airparif.internal.api.AirParifApi.Appreciation; import org.openhab.core.library.unit.Units; import com.google.gson.annotations.SerializedName; @@ -28,29 +30,37 @@ import com.google.gson.annotations.SerializedName; */ @NonNullByDefault public enum Pollutant { + // Concentration thresholds per pollutant are available here: + // https://www.airparif.fr/sites/default/files/pdf/guide_calcul_nouvel_indice_fedeAtmo_14122020.pdf + @SerializedName("pm25") - PM25(Units.MICROGRAM_PER_CUBICMETRE), + PM25(Units.MICROGRAM_PER_CUBICMETRE, new int[] { 10, 20, 25, 50, 75 }), @SerializedName("pm10") - PM10(Units.MICROGRAM_PER_CUBICMETRE), + PM10(Units.MICROGRAM_PER_CUBICMETRE, new int[] { 20, 40, 50, 100, 150 }), @SerializedName("no2") - NO2(Units.PARTS_PER_BILLION), + NO2(Units.MICROGRAM_PER_CUBICMETRE, new int[] { 40, 90, 120, 230, 340 }), @SerializedName("o3") - O3(Units.PARTS_PER_BILLION), + O3(Units.MICROGRAM_PER_CUBICMETRE, new int[] { 50, 100, 130, 240, 380 }), + + @SerializedName("so2") + SO2(Units.MICROGRAM_PER_CUBICMETRE, new int[] { 100, 200, 350, 500, 750 }), @SerializedName("indice") - INDICE(Units.PERCENT), + INDICE(null, new int[] {}), - UNKNOWN(Units.PERCENT); + UNKNOWN(null, new int[] {}); public static final EnumSet AS_SET = EnumSet.allOf(Pollutant.class); - public final Unit unit; + public final @Nullable Unit unit; + private final int[] thresholds; - Pollutant(Unit unit) { + Pollutant(@Nullable Unit unit, int[] thresholds) { this.unit = unit; + this.thresholds = thresholds; } public static Pollutant safeValueOf(String searched) { @@ -60,4 +70,21 @@ public enum Pollutant { return Pollutant.UNKNOWN; } } + + public boolean hasUnit() { + return unit != null; + } + + public Appreciation getAppreciation(double concentration) { + if (thresholds.length == 0) { + return Appreciation.UNKNOWN; + } + + for (int i = 0; i < thresholds.length; i++) { + if (concentration <= thresholds[i]) { + return Appreciation.values()[i]; + } + } + return Appreciation.EXTREMELY_BAD; + } } diff --git a/bundles/org.openhab.binding.airparif/src/main/java/org/openhab/binding/airparif/internal/handler/AirParifBridgeHandler.java b/bundles/org.openhab.binding.airparif/src/main/java/org/openhab/binding/airparif/internal/handler/AirParifBridgeHandler.java index c106fdcef1c..efdc27e31be 100755 --- a/bundles/org.openhab.binding.airparif/src/main/java/org/openhab/binding/airparif/internal/handler/AirParifBridgeHandler.java +++ b/bundles/org.openhab.binding.airparif/src/main/java/org/openhab/binding/airparif/internal/handler/AirParifBridgeHandler.java @@ -48,7 +48,6 @@ import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpStatus.Code; import org.openhab.binding.airparif.internal.AirParifException; -import org.openhab.binding.airparif.internal.AirParifIconProvider; import org.openhab.binding.airparif.internal.api.AirParifApi.Pollen; import org.openhab.binding.airparif.internal.api.AirParifDto.Bulletin; import org.openhab.binding.airparif.internal.api.AirParifDto.Episode; @@ -57,13 +56,11 @@ import org.openhab.binding.airparif.internal.api.AirParifDto.KeyInfo; import org.openhab.binding.airparif.internal.api.AirParifDto.PollensResponse; import org.openhab.binding.airparif.internal.api.AirParifDto.Route; import org.openhab.binding.airparif.internal.api.AirParifDto.Version; -import org.openhab.binding.airparif.internal.api.ColorMap; import org.openhab.binding.airparif.internal.api.PollenAlertLevel; import org.openhab.binding.airparif.internal.api.Pollutant; import org.openhab.binding.airparif.internal.config.BridgeConfiguration; import org.openhab.binding.airparif.internal.deserialization.AirParifDeserializer; import org.openhab.core.library.types.DateTimeType; -import org.openhab.core.library.types.QuantityType; import org.openhab.core.library.types.StringType; import org.openhab.core.thing.Bridge; import org.openhab.core.thing.ChannelGroupUID; @@ -97,17 +94,14 @@ public class AirParifBridgeHandler extends BaseBridgeHandler implements HandlerU private final Logger logger = LoggerFactory.getLogger(AirParifBridgeHandler.class); private final Map> jobs = new HashMap<>(); private final AirParifDeserializer deserializer; - private final AirParifIconProvider iconProvider; private final HttpClient httpClient; private BridgeConfiguration config = new BridgeConfiguration(); private @Nullable PollensResponse pollens; - public AirParifBridgeHandler(Bridge bridge, HttpClient httpClient, AirParifDeserializer deserializer, - AirParifIconProvider iconProvider) { + public AirParifBridgeHandler(Bridge bridge, HttpClient httpClient, AirParifDeserializer deserializer) { super(bridge); this.deserializer = deserializer; - this.iconProvider = iconProvider; this.httpClient = httpClient; } @@ -202,14 +196,6 @@ public class AirParifBridgeHandler extends BaseBridgeHandler implements HandlerU logger.info("The api key is valid until {}", keyInfo.expiration().toString()); updateStatus(ThingStatus.ONLINE); - try { - ColorMap map = executeUri(PREV_COLORS_URI, ColorMap.class); - logger.debug("The color map is {}", map.toString()); - iconProvider.setColorMap(map); - } catch (AirParifException e) { - logger.warn("Error reading ColorMap: {}", e.getMessage()); - } - ThingUID thingUID = thing.getUID(); schedule(POLLENS_JOB, () -> updatePollens(new ChannelGroupUID(thingUID, GROUP_POLLENS)), Duration.ofSeconds(1)); @@ -257,15 +243,15 @@ public class AirParifBridgeHandler extends BaseBridgeHandler implements HandlerU Set.of(bulletin.today(), bulletin.tomorrow()).stream().forEach(aq -> { ChannelGroupUID groupUID = aq.isToday() ? todayGroupUID : tomorrowGroupUID; updateState(new ChannelUID(groupUID, CHANNEL_COMMENT), - !aq.available() ? UnDefType.UNDEF : new StringType(aq.bulletin().fr())); + !aq.available() ? UnDefType.NULL : new StringType(aq.bulletin().fr())); aq.concentrations().forEach(measure -> { Pollutant pollutant = measure.pollutant(); String cName = pollutant.name().toLowerCase() + "-"; updateState(new ChannelUID(groupUID, cName + "min"), - aq.available() ? new QuantityType<>(measure.min(), pollutant.unit) : UnDefType.UNDEF); + aq.available() ? measure.getMin() : UnDefType.NULL); updateState(new ChannelUID(groupUID, cName + "max"), - aq.available() ? new QuantityType<>(measure.max(), pollutant.unit) : UnDefType.UNDEF); + aq.available() ? measure.getMax() : UnDefType.NULL); }); }); diff --git a/bundles/org.openhab.binding.airparif/src/main/java/org/openhab/binding/airparif/internal/handler/LocationHandler.java b/bundles/org.openhab.binding.airparif/src/main/java/org/openhab/binding/airparif/internal/handler/LocationHandler.java index f84175eff5b..ed58336d5fa 100755 --- a/bundles/org.openhab.binding.airparif/src/main/java/org/openhab/binding/airparif/internal/handler/LocationHandler.java +++ b/bundles/org.openhab.binding.airparif/src/main/java/org/openhab/binding/airparif/internal/handler/LocationHandler.java @@ -15,6 +15,7 @@ package org.openhab.binding.airparif.internal.handler; import static org.openhab.binding.airparif.internal.AirParifBindingConstants.*; import java.time.Duration; +import java.util.Comparator; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ScheduledExecutorService; @@ -23,13 +24,14 @@ import java.util.concurrent.ScheduledFuture; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.airparif.internal.api.AirParifApi.Pollen; +import org.openhab.binding.airparif.internal.api.AirParifDto.Concentration; import org.openhab.binding.airparif.internal.api.AirParifDto.PollensResponse; import org.openhab.binding.airparif.internal.api.AirParifDto.Route; import org.openhab.binding.airparif.internal.api.PollenAlertLevel; +import org.openhab.binding.airparif.internal.api.Pollutant; import org.openhab.binding.airparif.internal.config.LocationConfiguration; import org.openhab.core.library.types.DateTimeType; import org.openhab.core.library.types.DecimalType; -import org.openhab.core.library.types.QuantityType; import org.openhab.core.thing.Bridge; import org.openhab.core.thing.ChannelGroupUID; import org.openhab.core.thing.ChannelUID; @@ -100,14 +102,22 @@ public class LocationHandler extends BaseThingHandler implements HandlerUtils { Route route = apiHandler.getConcentrations(local.location); if (route != null) { - route.concentrations().forEach(concentration -> { - ChannelGroupUID groupUID = new ChannelGroupUID(thing.getUID(), - concentration.pollutant().name().toLowerCase()); - updateState(new ChannelUID(groupUID, CHANNEL_TIMESTAMP), new DateTimeType(concentration.date())); - updateState(new ChannelUID(groupUID, CHANNEL_MESSAGE), concentration.getMessage()); - updateState(new ChannelUID(groupUID, CHANNEL_VALUE), - new QuantityType<>(concentration.getValue(), concentration.pollutant().unit)); + int maxAlert = route.concentrations().stream().filter(conc -> conc.pollutant().hasUnit()) + .map(Concentration::getAlertLevel).max(Comparator.comparing(Integer::valueOf)).get(); + route.concentrations().stream().forEach(concentration -> { + Pollutant pollutant = concentration.pollutant(); + ChannelGroupUID groupUID = new ChannelGroupUID(thing.getUID(), pollutant.name().toLowerCase()); + updateState(new ChannelUID(groupUID, CHANNEL_MESSAGE), concentration.getMessage()); + if (!pollutant.hasUnit()) { + updateState(new ChannelUID(groupUID, CHANNEL_TIMESTAMP), + new DateTimeType(concentration.date())); + updateState(new ChannelUID(groupUID, CHANNEL_ALERT), new DecimalType(maxAlert)); + } else { + updateState(new ChannelUID(groupUID, CHANNEL_VALUE), concentration.getQuantity()); + updateState(new ChannelUID(groupUID, CHANNEL_ALERT), + new DecimalType(concentration.getAlertLevel())); + } }); updateStatus(ThingStatus.ONLINE); } diff --git a/bundles/org.openhab.binding.airparif/src/main/resources/OH-INF/i18n/airparif.properties b/bundles/org.openhab.binding.airparif/src/main/resources/OH-INF/i18n/airparif.properties index 850db294e30..23e096b9881 100755 --- a/bundles/org.openhab.binding.airparif/src/main/resources/OH-INF/i18n/airparif.properties +++ b/bundles/org.openhab.binding.airparif/src/main/resources/OH-INF/i18n/airparif.properties @@ -67,26 +67,19 @@ channel-group-type.airparif.daily.channel.tomorrow.label = Tomorrow channel-group-type.airparif.daily.channel.tomorrow.description = Current bulletin validity start channel-group-type.airparif.dept-pollens.label = Pollen information for the department channel-group-type.airparif.pollutant-mpc.label = Pollutant Concentration Information +channel-group-type.airparif.pollutant-mpc.channel.alert.label = Alert Level +channel-group-type.airparif.pollutant-mpc.channel.alert.description = Alert Level associated to pollutant concentration channel-group-type.airparif.pollutant-mpc.channel.message.label = Message channel-group-type.airparif.pollutant-mpc.channel.message.description = Polllutant concentration alert message -channel-group-type.airparif.pollutant-mpc.channel.timestamp.label = Timestamp -channel-group-type.airparif.pollutant-mpc.channel.timestamp.description = Timestamp of the measure channel-group-type.airparif.pollutant-mpc.channel.value.label = Concentration channel-group-type.airparif.pollutant-mpc.channel.value.description = Concentration of the given pollutant channel-group-type.airparif.pollutant-ndx.label = Global Pollutant Index +channel-group-type.airparif.pollutant-ndx.channel.alert.label = Alert Level +channel-group-type.airparif.pollutant-ndx.channel.alert.description = Alert Level associated to highest pollutant concentration channel-group-type.airparif.pollutant-ndx.channel.message.label = Message channel-group-type.airparif.pollutant-ndx.channel.message.description = Alert message associated to the value of the index channel-group-type.airparif.pollutant-ndx.channel.timestamp.label = Timestamp channel-group-type.airparif.pollutant-ndx.channel.timestamp.description = Timestamp of the evaluation -channel-group-type.airparif.pollutant-ndx.channel.value.label = Value -channel-group-type.airparif.pollutant-ndx.channel.value.description = Value of the global Index -channel-group-type.airparif.pollutant-ppb.label = Pollutant Concentration Information -channel-group-type.airparif.pollutant-ppb.channel.message.label = Message -channel-group-type.airparif.pollutant-ppb.channel.message.description = Polllutant concentration alert message -channel-group-type.airparif.pollutant-ppb.channel.timestamp.label = Timestamp -channel-group-type.airparif.pollutant-ppb.channel.timestamp.description = Timestamp of the measure -channel-group-type.airparif.pollutant-ppb.channel.value.label = Concentration -channel-group-type.airparif.pollutant-ppb.channel.value.description = Concentration of the given pollutant # channel types @@ -95,6 +88,13 @@ channel-type.airparif.alder-level.state.option.0 = None channel-type.airparif.alder-level.state.option.1 = Low channel-type.airparif.alder-level.state.option.2 = Average channel-type.airparif.alder-level.state.option.3 = High +channel-type.airparif.appreciation.label = Air Quality +channel-type.airparif.appreciation.state.option.0 = Good +channel-type.airparif.appreciation.state.option.1 = Average +channel-type.airparif.appreciation.state.option.2 = Degrated +channel-type.airparif.appreciation.state.option.3 = Bad +channel-type.airparif.appreciation.state.option.4 = Very Bad +channel-type.airparif.appreciation.state.option.5 = Extremely Bad channel-type.airparif.ash-level.label = Ash channel-type.airparif.ash-level.state.option.0 = None channel-type.airparif.ash-level.state.option.1 = Low @@ -163,7 +163,6 @@ channel-type.airparif.poplar-level.state.option.0 = None channel-type.airparif.poplar-level.state.option.1 = Low channel-type.airparif.poplar-level.state.option.2 = Average channel-type.airparif.poplar-level.state.option.3 = High -channel-type.airparif.ppb-value.label = Measure channel-type.airparif.ragweed-level.label = Ragweed channel-type.airparif.ragweed-level.state.option.0 = None channel-type.airparif.ragweed-level.state.option.1 = Low @@ -191,6 +190,24 @@ channel-type.airparif.wormwood-level.state.option.1 = Low channel-type.airparif.wormwood-level.state.option.2 = Average channel-type.airparif.wormwood-level.state.option.3 = High +# channel group types + +channel-group-type.airparif.pollutant-mpc.channel.timestamp.label = Timestamp +channel-group-type.airparif.pollutant-mpc.channel.timestamp.description = Timestamp of the measure +channel-group-type.airparif.pollutant-ndx.channel.value.label = Value +channel-group-type.airparif.pollutant-ndx.channel.value.description = Value of the global Index +channel-group-type.airparif.pollutant-ppb.label = Pollutant Concentration Information +channel-group-type.airparif.pollutant-ppb.channel.message.label = Message +channel-group-type.airparif.pollutant-ppb.channel.message.description = Polllutant concentration alert message +channel-group-type.airparif.pollutant-ppb.channel.timestamp.label = Timestamp +channel-group-type.airparif.pollutant-ppb.channel.timestamp.description = Timestamp of the measure +channel-group-type.airparif.pollutant-ppb.channel.value.label = Concentration +channel-group-type.airparif.pollutant-ppb.channel.value.description = Concentration of the given pollutant + +# channel types + +channel-type.airparif.ppb-value.label = Measure + # thing types thing-type.airparif.location.channel.end-validity.label = End Of Validity diff --git a/bundles/org.openhab.binding.airparif/src/main/resources/OH-INF/thing/channel-groups.xml b/bundles/org.openhab.binding.airparif/src/main/resources/OH-INF/thing/channel-groups.xml index 5494219bbcb..d84547ff8ed 100644 --- a/bundles/org.openhab.binding.airparif/src/main/resources/OH-INF/thing/channel-groups.xml +++ b/bundles/org.openhab.binding.airparif/src/main/resources/OH-INF/thing/channel-groups.xml @@ -29,19 +29,19 @@ General message for the air quality bulletin - + Minimum level of NO2 concentation - + Maximum level of NO2 concentation - + Minimum level of O3 concentation - + Maximum level of O3 concentation @@ -71,31 +71,13 @@ Polllutant concentration alert message - - - Timestamp of the measure - Concentration of the given pollutant - - - - - - - - - Polllutant concentration alert message - - - - Timestamp of the measure - - - - Concentration of the given pollutant + + + Alert Level associated to pollutant concentration @@ -111,9 +93,9 @@ Timestamp of the evaluation - - - Value of the global Index + + + Alert Level associated to highest pollutant concentration diff --git a/bundles/org.openhab.binding.airparif/src/main/resources/OH-INF/thing/channels.xml b/bundles/org.openhab.binding.airparif/src/main/resources/OH-INF/thing/channels.xml index e47a4ec856c..18810b36d3f 100755 --- a/bundles/org.openhab.binding.airparif/src/main/resources/OH-INF/thing/channels.xml +++ b/bundles/org.openhab.binding.airparif/src/main/resources/OH-INF/thing/channels.xml @@ -291,12 +291,6 @@ - - Number:Dimensionless - - - - Number @@ -309,5 +303,21 @@ + + Number + + oh:airparif:aq + + + + + + + + + + + + diff --git a/bundles/org.openhab.binding.airparif/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.airparif/src/main/resources/OH-INF/thing/thing-types.xml index 80003f5c0e9..bf92bdc8ed2 100755 --- a/bundles/org.openhab.binding.airparif/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.airparif/src/main/resources/OH-INF/thing/thing-types.xml @@ -15,10 +15,10 @@ - + - + diff --git a/bundles/org.openhab.binding.airparif/src/main/resources/icon/alder.svg b/bundles/org.openhab.binding.airparif/src/main/resources/icon/alder.svg old mode 100644 new mode 100755 diff --git a/bundles/org.openhab.binding.airparif/src/main/resources/icon/aq-0.svg b/bundles/org.openhab.binding.airparif/src/main/resources/icon/aq-0.svg new file mode 100755 index 00000000000..80e94fe7fd2 --- /dev/null +++ b/bundles/org.openhab.binding.airparif/src/main/resources/icon/aq-0.svg @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/bundles/org.openhab.binding.airparif/src/main/resources/icon/aq-1.svg b/bundles/org.openhab.binding.airparif/src/main/resources/icon/aq-1.svg new file mode 100755 index 00000000000..2e78da14543 --- /dev/null +++ b/bundles/org.openhab.binding.airparif/src/main/resources/icon/aq-1.svg @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/bundles/org.openhab.binding.airparif/src/main/resources/icon/aq-2.svg b/bundles/org.openhab.binding.airparif/src/main/resources/icon/aq-2.svg new file mode 100755 index 00000000000..a7b3aa5ac8f --- /dev/null +++ b/bundles/org.openhab.binding.airparif/src/main/resources/icon/aq-2.svg @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/bundles/org.openhab.binding.airparif/src/main/resources/icon/aq-3.svg b/bundles/org.openhab.binding.airparif/src/main/resources/icon/aq-3.svg new file mode 100755 index 00000000000..547740458c9 --- /dev/null +++ b/bundles/org.openhab.binding.airparif/src/main/resources/icon/aq-3.svg @@ -0,0 +1,9 @@ + + + + + + + \ No newline at end of file diff --git a/bundles/org.openhab.binding.airparif/src/main/resources/icon/aq-4.svg b/bundles/org.openhab.binding.airparif/src/main/resources/icon/aq-4.svg new file mode 100755 index 00000000000..8db5142887d --- /dev/null +++ b/bundles/org.openhab.binding.airparif/src/main/resources/icon/aq-4.svg @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/bundles/org.openhab.binding.airparif/src/main/resources/icon/aq-5.svg b/bundles/org.openhab.binding.airparif/src/main/resources/icon/aq-5.svg new file mode 100755 index 00000000000..80b94df18ba --- /dev/null +++ b/bundles/org.openhab.binding.airparif/src/main/resources/icon/aq-5.svg @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/bundles/org.openhab.binding.airparif/src/main/resources/icon/aq.svg b/bundles/org.openhab.binding.airparif/src/main/resources/icon/aq.svg new file mode 100755 index 00000000000..056c569a4a6 --- /dev/null +++ b/bundles/org.openhab.binding.airparif/src/main/resources/icon/aq.svg @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/bundles/org.openhab.binding.airparif/src/main/resources/icon/ash.svg b/bundles/org.openhab.binding.airparif/src/main/resources/icon/ash.svg old mode 100644 new mode 100755 diff --git a/bundles/org.openhab.binding.airparif/src/main/resources/icon/average.svg b/bundles/org.openhab.binding.airparif/src/main/resources/icon/average.svg deleted file mode 100644 index f690930b938..00000000000 --- a/bundles/org.openhab.binding.airparif/src/main/resources/icon/average.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - diff --git a/bundles/org.openhab.binding.airparif/src/main/resources/icon/bad.svg b/bundles/org.openhab.binding.airparif/src/main/resources/icon/bad.svg deleted file mode 100644 index aff876d3508..00000000000 --- a/bundles/org.openhab.binding.airparif/src/main/resources/icon/bad.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - diff --git a/bundles/org.openhab.binding.airparif/src/main/resources/icon/birch.svg b/bundles/org.openhab.binding.airparif/src/main/resources/icon/birch.svg old mode 100644 new mode 100755 diff --git a/bundles/org.openhab.binding.airparif/src/main/resources/icon/chestnut.svg b/bundles/org.openhab.binding.airparif/src/main/resources/icon/chestnut.svg old mode 100644 new mode 100755 diff --git a/bundles/org.openhab.binding.airparif/src/main/resources/icon/cypress.svg b/bundles/org.openhab.binding.airparif/src/main/resources/icon/cypress.svg old mode 100644 new mode 100755 diff --git a/bundles/org.openhab.binding.airparif/src/main/resources/icon/degrated.svg b/bundles/org.openhab.binding.airparif/src/main/resources/icon/degrated.svg deleted file mode 100644 index df239efc873..00000000000 --- a/bundles/org.openhab.binding.airparif/src/main/resources/icon/degrated.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - diff --git a/bundles/org.openhab.binding.airparif/src/main/resources/icon/extremely-bad.svg b/bundles/org.openhab.binding.airparif/src/main/resources/icon/extremely-bad.svg deleted file mode 100644 index bce1d6ef083..00000000000 --- a/bundles/org.openhab.binding.airparif/src/main/resources/icon/extremely-bad.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - diff --git a/bundles/org.openhab.binding.airparif/src/main/resources/icon/good.svg b/bundles/org.openhab.binding.airparif/src/main/resources/icon/good.svg deleted file mode 100644 index 22a5d524ec6..00000000000 --- a/bundles/org.openhab.binding.airparif/src/main/resources/icon/good.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - diff --git a/bundles/org.openhab.binding.airparif/src/main/resources/icon/grasses.svg b/bundles/org.openhab.binding.airparif/src/main/resources/icon/grasses.svg old mode 100644 new mode 100755 diff --git a/bundles/org.openhab.binding.airparif/src/main/resources/icon/hazel.svg b/bundles/org.openhab.binding.airparif/src/main/resources/icon/hazel.svg old mode 100644 new mode 100755 diff --git a/bundles/org.openhab.binding.airparif/src/main/resources/icon/hornbeam.svg b/bundles/org.openhab.binding.airparif/src/main/resources/icon/hornbeam.svg old mode 100644 new mode 100755 diff --git a/bundles/org.openhab.binding.airparif/src/main/resources/icon/linden.svg b/bundles/org.openhab.binding.airparif/src/main/resources/icon/linden.svg old mode 100644 new mode 100755 diff --git a/bundles/org.openhab.binding.airparif/src/main/resources/icon/oak.svg b/bundles/org.openhab.binding.airparif/src/main/resources/icon/oak.svg old mode 100644 new mode 100755 diff --git a/bundles/org.openhab.binding.airparif/src/main/resources/icon/olive.svg b/bundles/org.openhab.binding.airparif/src/main/resources/icon/olive.svg old mode 100644 new mode 100755 diff --git a/bundles/org.openhab.binding.airparif/src/main/resources/icon/plane.svg b/bundles/org.openhab.binding.airparif/src/main/resources/icon/plane.svg old mode 100644 new mode 100755 diff --git a/bundles/org.openhab.binding.airparif/src/main/resources/icon/plantain.svg b/bundles/org.openhab.binding.airparif/src/main/resources/icon/plantain.svg old mode 100644 new mode 100755 diff --git a/bundles/org.openhab.binding.airparif/src/main/resources/icon/pollen.svg b/bundles/org.openhab.binding.airparif/src/main/resources/icon/pollen.svg old mode 100644 new mode 100755 diff --git a/bundles/org.openhab.binding.airparif/src/main/resources/icon/poplar.svg b/bundles/org.openhab.binding.airparif/src/main/resources/icon/poplar.svg old mode 100644 new mode 100755 diff --git a/bundles/org.openhab.binding.airparif/src/main/resources/icon/ragweed.svg b/bundles/org.openhab.binding.airparif/src/main/resources/icon/ragweed.svg old mode 100644 new mode 100755 diff --git a/bundles/org.openhab.binding.airparif/src/main/resources/icon/rumex.svg b/bundles/org.openhab.binding.airparif/src/main/resources/icon/rumex.svg old mode 100644 new mode 100755 diff --git a/bundles/org.openhab.binding.airparif/src/main/resources/icon/urticaceae.svg b/bundles/org.openhab.binding.airparif/src/main/resources/icon/urticaceae.svg old mode 100644 new mode 100755 diff --git a/bundles/org.openhab.binding.airparif/src/main/resources/icon/willow.svg b/bundles/org.openhab.binding.airparif/src/main/resources/icon/willow.svg old mode 100644 new mode 100755 diff --git a/bundles/org.openhab.binding.airparif/src/main/resources/icon/wormwood.svg b/bundles/org.openhab.binding.airparif/src/main/resources/icon/wormwood.svg old mode 100644 new mode 100755