From 48dcb27a61821e98d1ca72d8289629c7a58c970c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20L=27hopital?= Date: Fri, 4 Dec 2020 02:31:18 +0100 Subject: [PATCH] [OpenUV] Issue when UV index < 1 (#9198) * [OpenUV] Correcting incorrect behaviour when UV < 1 and some code enhancements * Correcting SAT findings * Initiating bundle localization in French Signed-off-by: clinique --- bundles/org.openhab.binding.openuv/README.md | 3 +- .../config/SafeExposureConfiguration.java | 2 +- .../internal/handler/OpenUVBridgeHandler.java | 36 ++++----- .../internal/handler/OpenUVReportHandler.java | 27 ++----- .../openuv/internal/json/OpenUVResponse.java | 12 ++- .../openuv/internal/json/OpenUVResult.java | 76 +++++++++++++------ .../internal/json/SafeExposureTime.java | 62 --------------- .../OH-INF/i18n/openuv_fr.properties | 10 +++ .../resources/OH-INF/thing/thing-types.xml | 34 +++++---- 9 files changed, 119 insertions(+), 143 deletions(-) delete mode 100644 bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/json/SafeExposureTime.java create mode 100644 bundles/org.openhab.binding.openuv/src/main/resources/OH-INF/i18n/openuv_fr.properties diff --git a/bundles/org.openhab.binding.openuv/README.md b/bundles/org.openhab.binding.openuv/README.md index 318415486..2a304799e 100644 --- a/bundles/org.openhab.binding.openuv/README.md +++ b/bundles/org.openhab.binding.openuv/README.md @@ -52,7 +52,8 @@ The OpenUV Report thing that is retrieved has these channels: | Channel ID | Item Type | Description | |--------------|---------------------|-------------------------------------------------| | UVIndex | Number | UV Index | -| UVColor | Color | Color associated to given UV Index. | +| Alert | Number | Alert level associated to given UV Index | +| UVColor | Color | Color associated to given alert level. | | UVMax | Number | Max UV Index for the day (at solar noon) | | UVMaxTime | DateTime | Max UV Index datetime (solar noon) | | Ozone | Number:ArealDensity | Ozone level in du (Dobson Units) from OMI data | diff --git a/bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/config/SafeExposureConfiguration.java b/bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/config/SafeExposureConfiguration.java index a78eb3fcf..d3006a3ad 100644 --- a/bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/config/SafeExposureConfiguration.java +++ b/bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/config/SafeExposureConfiguration.java @@ -22,5 +22,5 @@ import org.eclipse.jdt.annotation.NonNullByDefault; */ @NonNullByDefault public class SafeExposureConfiguration { - public int index = -1; + public String index = "II"; } diff --git a/bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/handler/OpenUVBridgeHandler.java b/bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/handler/OpenUVBridgeHandler.java index b3fb8a161..afb611042 100644 --- a/bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/handler/OpenUVBridgeHandler.java +++ b/bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/handler/OpenUVBridgeHandler.java @@ -54,16 +54,14 @@ import com.google.gson.Gson; */ @NonNullByDefault public class OpenUVBridgeHandler extends BaseBridgeHandler { - private final Logger logger = LoggerFactory.getLogger(OpenUVBridgeHandler.class); - private static final String QUERY_URL = "https://api.openuv.io/api/v1/uv?lat=%s&lng=%s&alt=%s"; - private static final int REQUEST_TIMEOUT_MS = (int) TimeUnit.SECONDS.toMillis(30); + private final Logger logger = LoggerFactory.getLogger(OpenUVBridgeHandler.class); private final Properties header = new Properties(); private final Gson gson; - private final LocationProvider locationProvider; + private @Nullable ScheduledFuture reconnectJob; public OpenUVBridgeHandler(Bridge bridge, LocationProvider locationProvider, Gson gson) { @@ -79,10 +77,10 @@ public class OpenUVBridgeHandler extends BaseBridgeHandler { if (config.apikey.isEmpty()) { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Parameter 'apikey' must be configured."); - } else { - header.put("x-access-token", config.apikey); - initiateConnexion(); + return; } + header.put("x-access-token", config.apikey); + initiateConnexion(); } @Override @@ -98,13 +96,13 @@ public class OpenUVBridgeHandler extends BaseBridgeHandler { public void handleCommand(ChannelUID channelUID, Command command) { if (command instanceof RefreshType) { initiateConnexion(); - } else { - logger.debug("The OpenUV bridge only handles Refresh command and not '{}'", command); + return; } + logger.debug("The OpenUV bridge only handles Refresh command and not '{}'", command); } private void initiateConnexion() { - // Check if the provided api key is valid for use with the OpenUV service + // Just checking if the provided api key is a valid one by making a fake call getUVData("0", "0", "0"); } @@ -113,11 +111,13 @@ public class OpenUVBridgeHandler extends BaseBridgeHandler { String jsonData = HttpUtil.executeUrl("GET", String.format(QUERY_URL, latitude, longitude, altitude), header, null, null, REQUEST_TIMEOUT_MS); OpenUVResponse uvResponse = gson.fromJson(jsonData, OpenUVResponse.class); - if (uvResponse.getError() == null) { - updateStatus(ThingStatus.ONLINE); - return uvResponse.getResult(); - } else { - throw new OpenUVException(uvResponse.getError()); + if (uvResponse != null) { + String error = uvResponse.getError(); + if (error == null) { + updateStatus(ThingStatus.ONLINE); + return uvResponse.getResult(); + } + throw new OpenUVException(error); } } catch (IOException e) { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage()); @@ -133,10 +133,10 @@ public class OpenUVBridgeHandler extends BaseBridgeHandler { reconnectJob = scheduler.schedule(this::initiateConnexion, Duration.between(LocalDateTime.now(), tomorrowMidnight).toMinutes(), TimeUnit.MINUTES); - } else if (e.isApiKeyError()) { - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage()); } else { - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, e.getMessage()); + updateStatus(ThingStatus.OFFLINE, + e.isApiKeyError() ? ThingStatusDetail.CONFIGURATION_ERROR : ThingStatusDetail.NONE, + e.getMessage()); } } return null; diff --git a/bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/handler/OpenUVReportHandler.java b/bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/handler/OpenUVReportHandler.java index f0622f345..ee3472955 100644 --- a/bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/handler/OpenUVReportHandler.java +++ b/bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/handler/OpenUVReportHandler.java @@ -21,8 +21,6 @@ import java.util.Map; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; -import javax.measure.quantity.Angle; - import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.openuv.internal.config.ReportConfiguration; @@ -174,7 +172,6 @@ public class OpenUVReportHandler extends BaseThingHandler { uvMaxJob = null; } - @SuppressWarnings("unchecked") @Override public void handleCommand(ChannelUID channelUID, Command command) { if (command instanceof RefreshType) { @@ -184,8 +181,8 @@ public class OpenUVReportHandler extends BaseThingHandler { }); } else if (ELEVATION.equals(channelUID.getId()) && command instanceof QuantityType) { QuantityType qtty = (QuantityType) command; - if ("°".equals(qtty.getUnit().toString())) { - suspendUpdates = ((QuantityType) qtty).doubleValue() < 0; + if (qtty.getUnit() == SmartHomeUnits.DEGREE_ANGLE) { + suspendUpdates = qtty.doubleValue() < 0; } else { logger.info("The OpenUV Report handles Sun Elevation of Number:Angle type, {} does not fit.", command); } @@ -208,7 +205,7 @@ public class OpenUVReportHandler extends BaseThingHandler { if (channelTypeUID != null) { switch (channelTypeUID.getId()) { case UV_INDEX: - updateState(channelUID, asDecimalType(openUVData.getUv())); + updateState(channelUID, new DecimalType(openUVData.getUv())); break; case ALERT_LEVEL: updateState(channelUID, asAlertLevel(openUVData.getUv())); @@ -218,7 +215,7 @@ public class OpenUVReportHandler extends BaseThingHandler { ALERT_COLORS.getOrDefault(asAlertLevel(openUVData.getUv()), ALERT_UNDEF)); break; case UV_MAX: - updateState(channelUID, asDecimalType(openUVData.getUvMax())); + updateState(channelUID, new DecimalType(openUVData.getUvMax())); break; case OZONE: updateState(channelUID, new QuantityType<>(openUVData.getOzone(), SmartHomeUnits.DOBSON_UNIT)); @@ -235,24 +232,14 @@ public class OpenUVReportHandler extends BaseThingHandler { case SAFE_EXPOSURE: SafeExposureConfiguration configuration = channel.getConfiguration() .as(SafeExposureConfiguration.class); - if (configuration.index != -1) { - updateState(channelUID, - openUVData.getSafeExposureTime().getSafeExposure(configuration.index)); - } + updateState(channelUID, openUVData.getSafeExposureTime(configuration.index)); break; } } } } - private State asDecimalType(int uv) { - if (uv >= 1) { - return new DecimalType(uv); - } - return UnDefType.NULL; - } - - private State asAlertLevel(int uv) { + private State asAlertLevel(double uv) { if (uv >= 11) { return ALERT_PURPLE; } else if (uv >= 8) { @@ -261,7 +248,7 @@ public class OpenUVReportHandler extends BaseThingHandler { return ALERT_ORANGE; } else if (uv >= 3) { return ALERT_YELLOW; - } else if (uv >= 1) { + } else if (uv > 0) { return ALERT_GREEN; } return UnDefType.NULL; diff --git a/bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/json/OpenUVResponse.java b/bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/json/OpenUVResponse.java index 5b22d92cd..660fd5577 100644 --- a/bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/json/OpenUVResponse.java +++ b/bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/json/OpenUVResponse.java @@ -12,21 +12,25 @@ */ package org.openhab.binding.openuv.internal.json; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; + /** * The {@link OpenUVResponse} is the Java class used to map the JSON * response to the OpenUV request. * * @author Gaël L'hopital - Initial contribution */ +@NonNullByDefault public class OpenUVResponse { - private String error; - private OpenUVResult result; + private @Nullable String error; + private @Nullable OpenUVResult result; - public OpenUVResult getResult() { + public @Nullable OpenUVResult getResult() { return result; } - public String getError() { + public @Nullable String getError() { return error; } } diff --git a/bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/json/OpenUVResult.java b/bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/json/OpenUVResult.java index 88b8dd334..95ed240f8 100644 --- a/bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/json/OpenUVResult.java +++ b/bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/json/OpenUVResult.java @@ -12,14 +12,21 @@ */ package org.openhab.binding.openuv.internal.json; -import java.time.LocalDateTime; -import java.time.ZoneId; import java.time.ZonedDateTime; +import java.util.HashMap; +import java.util.Map; import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; import org.openhab.core.library.types.DateTimeType; +import org.openhab.core.library.types.QuantityType; +import org.openhab.core.library.unit.SmartHomeUnits; import org.openhab.core.types.State; import org.openhab.core.types.UnDefType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.annotations.SerializedName; /** * The {@link OpenUVResult} is responsible for storing @@ -29,21 +36,37 @@ import org.openhab.core.types.UnDefType; */ @NonNullByDefault public class OpenUVResult { - private final ZonedDateTime DEFAULT_ZDT = ZonedDateTime.of(LocalDateTime.MIN, ZoneId.systemDefault()); - private double uv; - private ZonedDateTime uvTime = DEFAULT_ZDT; - private double uvMax; - private ZonedDateTime uvMaxTime = DEFAULT_ZDT; - private double ozone; - private ZonedDateTime ozoneTime = DEFAULT_ZDT; - private SafeExposureTime safeExposureTime = new SafeExposureTime(); + private final Logger logger = LoggerFactory.getLogger(OpenUVResult.class); - public int getUv() { - return (int) uv; + public enum FitzpatrickType { + @SerializedName("st1") + I, // Fitzpatrick Skin Type I + @SerializedName("st2") + II, // Fitzpatrick Skin Type II + @SerializedName("st3") + III, // Fitzpatrick Skin Type III + @SerializedName("st4") + IV, // Fitzpatrick Skin Type IV + @SerializedName("st5") + V, // Fitzpatrick Skin Type V + @SerializedName("st6") + VI;// Fitzpatrick Skin Type VI } - public int getUvMax() { - return (int) uvMax; + private double uv; + private @Nullable ZonedDateTime uvTime; + private double uvMax; + private @Nullable ZonedDateTime uvMaxTime; + private double ozone; + private @Nullable ZonedDateTime ozoneTime; + private Map safeExposureTime = new HashMap<>(); + + public double getUv() { + return uv; + } + + public double getUvMax() { + return uvMax; } public double getOzone() { @@ -51,21 +74,30 @@ public class OpenUVResult { } public State getUVTime() { - return uvTime != DEFAULT_ZDT ? new DateTimeType(uvTime.withZoneSameInstant(ZoneId.systemDefault())) - : UnDefType.NULL; + ZonedDateTime value = uvTime; + return value != null ? new DateTimeType(value) : UnDefType.NULL; } public State getUVMaxTime() { - return uvMaxTime != DEFAULT_ZDT ? new DateTimeType(uvMaxTime.withZoneSameInstant(ZoneId.systemDefault())) - : UnDefType.NULL; + ZonedDateTime value = uvMaxTime; + return value != null ? new DateTimeType(value) : UnDefType.NULL; } public State getOzoneTime() { - return ozoneTime != DEFAULT_ZDT ? new DateTimeType(ozoneTime.withZoneSameInstant(ZoneId.systemDefault())) - : UnDefType.NULL; + ZonedDateTime value = ozoneTime; + return value != null ? new DateTimeType(value) : UnDefType.NULL; } - public SafeExposureTime getSafeExposureTime() { - return safeExposureTime; + public State getSafeExposureTime(String index) { + try { + FitzpatrickType value = FitzpatrickType.valueOf(index); + Integer duration = safeExposureTime.get(value); + if (duration != null) { + return new QuantityType<>(duration, SmartHomeUnits.MINUTE); + } + } catch (IllegalArgumentException e) { + logger.warn("Unexpected Fitzpatrick index value '{}' : {}", index, e.getMessage()); + } + return UnDefType.NULL; } } diff --git a/bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/json/SafeExposureTime.java b/bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/json/SafeExposureTime.java deleted file mode 100644 index 4b8b1dfb1..000000000 --- a/bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/json/SafeExposureTime.java +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.binding.openuv.internal.json; - -import java.math.BigInteger; - -import org.eclipse.jdt.annotation.Nullable; -import org.openhab.core.library.types.QuantityType; -import org.openhab.core.library.unit.SmartHomeUnits; -import org.openhab.core.types.State; -import org.openhab.core.types.UnDefType; - -/** - * Wrapper type around values reported by OpenUV safe exposure time. - * - * @author Gaël L'hopital - Initial contribution - */ -public class SafeExposureTime { - public @Nullable BigInteger st1; - public @Nullable BigInteger st2; - public @Nullable BigInteger st3; - public @Nullable BigInteger st4; - public @Nullable BigInteger st5; - public @Nullable BigInteger st6; - - public State getSafeExposure(int index) { - BigInteger result; - switch (index) { - case 1: - result = st1; - break; - case 2: - result = st2; - break; - case 3: - result = st3; - break; - case 4: - result = st4; - break; - case 5: - result = st5; - break; - case 6: - result = st6; - break; - default: - result = null; - } - return (result != null) ? new QuantityType<>(result, SmartHomeUnits.MINUTE) : UnDefType.NULL; - } -} diff --git a/bundles/org.openhab.binding.openuv/src/main/resources/OH-INF/i18n/openuv_fr.properties b/bundles/org.openhab.binding.openuv/src/main/resources/OH-INF/i18n/openuv_fr.properties new file mode 100644 index 000000000..5a0d74d38 --- /dev/null +++ b/bundles/org.openhab.binding.openuv/src/main/resources/OH-INF/i18n/openuv_fr.properties @@ -0,0 +1,10 @@ +# binding +binding.openuv.name = Extension OpenUV +binding.openuv.description = Service de prévision globale de l'indice UV en temps réel. + +# thing types +thing-type.openuv.openuvapi.label = Bridge OpenUV +thing-type.openuv.openuvapi.description = Passerelle vers le service du projet OpenUV. Pour recevoir des données vous devez créer votre compte à l'adresse https://www.openuv.io/auth/google et obtenir votre clef API. + +thing-type.openuv.uvreport.label = Rapport UV +thing-type.openuv.uvreport.description = Fournit diverses information pour un emplacement donnée. diff --git a/bundles/org.openhab.binding.openuv/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.openuv/src/main/resources/OH-INF/thing/thing-types.xml index dc96bb92c..bb0fb8797 100644 --- a/bundles/org.openhab.binding.openuv/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.openuv/src/main/resources/OH-INF/thing/thing-types.xml @@ -67,14 +67,14 @@ Number UV Index - + Number Max UV Index for the day (at solar noon) - + @@ -102,37 +102,39 @@ DateTime - - UV Index timestamp. + + UV Report timestamp. time Color - + Color associated to given UV Index alert level. + rgb Number:Time - Safe exposure time for Fitzpatrick Skin Types + Safe exposure duration for Fitzpatrick Skin Types. + time - + Fitzpatrick Skin Type. - - - - - - + + + + + + - 2 + II @@ -140,7 +142,8 @@ Number:Angle - The elevation of the sun + The elevation of the sun (should FOLLOW appropriate item). + niveau @@ -154,6 +157,7 @@ Number + alarm