]> git.basschouten.com Git - openhab-addons.git/commitdiff
[OpenUV] Issue when UV index < 1 (#9198)
authorGaël L'hopital <gael@lhopital.org>
Fri, 4 Dec 2020 01:31:18 +0000 (02:31 +0100)
committerGitHub <noreply@github.com>
Fri, 4 Dec 2020 01:31:18 +0000 (17:31 -0800)
* [OpenUV] Correcting incorrect behaviour when UV < 1
and some code enhancements
* Correcting SAT findings
* Initiating bundle localization in French

Signed-off-by: clinique <gael@lhopital.org>
bundles/org.openhab.binding.openuv/README.md
bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/config/SafeExposureConfiguration.java
bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/handler/OpenUVBridgeHandler.java
bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/handler/OpenUVReportHandler.java
bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/json/OpenUVResponse.java
bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/json/OpenUVResult.java
bundles/org.openhab.binding.openuv/src/main/java/org/openhab/binding/openuv/internal/json/SafeExposureTime.java [deleted file]
bundles/org.openhab.binding.openuv/src/main/resources/OH-INF/i18n/openuv_fr.properties [new file with mode: 0644]
bundles/org.openhab.binding.openuv/src/main/resources/OH-INF/thing/thing-types.xml

index 31841548634402b098d9dab90efbdd5ae88fe78d..2a304799ee218567ada67b1dd82e96ab3114bb5f 100644 (file)
@@ -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  |
index a78eb3fcfafdad732aed1869bfd533c940289f3c..d3006a3ad72eaa6212c7463a589ba7bb1f9f57f0 100644 (file)
@@ -22,5 +22,5 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
  */
 @NonNullByDefault
 public class SafeExposureConfiguration {
-    public int index = -1;
+    public String index = "II";
 }
index b3fb8a1614ccef5ebf555db58ef85e267b3a1a85..afb61104220bddc549deba1a92b3abe90eae0cc0 100644 (file)
@@ -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;
index f0622f345697b13f270c4af532f2f212874aa635..ee34729558b351a3fb63afa72338b32ccf185b80 100644 (file)
@@ -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<Angle>) 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;
index 5b22d92cdeca8ac9ebdea157cbf085189e061227..660fd557782c809d77039a076a9ca501378ace4f 100644 (file)
  */
 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;
     }
 }
index 88b8dd33420aed1cc56b58700b7cc5f82850d591..95ed240f85f260b3b8d9d262068ef44dd9373744 100644 (file)
  */
 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 final Logger logger = LoggerFactory.getLogger(OpenUVResult.class);
+
+    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
+    }
+
     private double uv;
-    private ZonedDateTime uvTime = DEFAULT_ZDT;
+    private @Nullable ZonedDateTime uvTime;
     private double uvMax;
-    private ZonedDateTime uvMaxTime = DEFAULT_ZDT;
+    private @Nullable ZonedDateTime uvMaxTime;
     private double ozone;
-    private ZonedDateTime ozoneTime = DEFAULT_ZDT;
-    private SafeExposureTime safeExposureTime = new SafeExposureTime();
+    private @Nullable ZonedDateTime ozoneTime;
+    private Map<FitzpatrickType, @Nullable Integer> safeExposureTime = new HashMap<>();
 
-    public int getUv() {
-        return (int) uv;
+    public double getUv() {
+        return uv;
     }
 
-    public int getUvMax() {
-        return (int) uvMax;
+    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 (file)
index 4b8b1df..0000000
+++ /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 (file)
index 0000000..5a0d74d
--- /dev/null
@@ -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.
index dc96bb92cf8230186e74a433fc677744b8a015ff..bb0fb87970a693a4b05764aa8a24e3e8a13f3fe9 100644 (file)
                <item-type>Number</item-type>
                <label>UV Index</label>
                <description>UV Index</description>
-               <state readOnly="true" pattern="%d/16" min="0" max="16"/>
+               <state readOnly="true" pattern="%.0f/16" min="0" max="16"/>
        </channel-type>
 
        <channel-type id="UVMax" advanced="true">
                <item-type>Number</item-type>
                <label>UV Max</label>
                <description>Max UV Index for the day (at solar noon)</description>
-               <state readOnly="true" pattern="%d/16" min="0" max="16"/>
+               <state readOnly="true" pattern="%.0f/16" min="0" max="16"/>
        </channel-type>
 
        <channel-type id="Ozone">
 
        <channel-type id="UVTime" advanced="true">
                <item-type>DateTime</item-type>
-               <label>UV Time</label>
-               <description>UV Index timestamp.</description>
+               <label>Report Timestamp</label>
+               <description>UV Report timestamp.</description>
                <category>time</category>
                <state readOnly="true" pattern="%1$tF %1$tR"/>
        </channel-type>
 
        <channel-type id="UVColor" advanced="true">
                <item-type>Color</item-type>
-               <label>UV Alert Color</label>
+               <label>Alert Color</label>
                <description>Color associated to given UV Index alert level.</description>
+               <category>rgb</category>
                <state readOnly="true"/>
        </channel-type>
 
        <channel-type id="SafeExposure" advanced="false">
                <item-type>Number:Time</item-type>
                <label>Safe Exposure</label>
-               <description>Safe exposure time for Fitzpatrick Skin Types</description>
+               <description>Safe exposure duration for Fitzpatrick Skin Types.</description>
+               <category>time</category>
                <state readOnly="true" pattern="%d %unit%"/>
                <config-description>
-                       <parameter name="index" type="integer">
+                       <parameter name="index" type="text">
                                <label>Skin Type</label>
                                <description>Fitzpatrick Skin Type.</description>
                                <options>
-                                       <option value="1">I – White</option>
-                                       <option value="2">II – White</option>
-                                       <option value="3">III – Light brown</option>
-                                       <option value="4">IV – Moderate brown</option>
-                                       <option value="5">V – Dark brown</option>
-                                       <option value="6">VI – Black</option>
+                                       <option value="I">Pale</option>
+                                       <option value="II">White</option>
+                                       <option value="III">Light brown</option>
+                                       <option value="IV">Moderate brown</option>
+                                       <option value="V">Dark brown</option>
+                                       <option value="VI">Black</option>
                                </options>
-                               <default>2</default>
+                               <default>II</default>
                        </parameter>
                </config-description>
        </channel-type>
        <channel-type id="elevation">
                <item-type>Number:Angle</item-type>
                <label>Elevation</label>
-               <description>The elevation of the sun</description>
+               <description>The elevation of the sun (should FOLLOW appropriate item).</description>
+               <category>niveau</category>
                <state pattern="%.2f %unit%"/>
        </channel-type>
 
        <channel-type id="Alert">
                <item-type>Number</item-type>
                <label>UV Alert</label>
+               <category>alarm</category>
                <state readOnly="true">
                        <options>
                                <option value="0">Low</option>