Skip to content

Commit

Permalink
[OpenUV] Issue when UV index < 1 (#9198)
Browse files Browse the repository at this point in the history
* [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>
  • Loading branch information
clinique committed Dec 4, 2020
1 parent b27ddbe commit 48dcb27
Show file tree
Hide file tree
Showing 9 changed files with 116 additions and 140 deletions.
3 changes: 2 additions & 1 deletion bundles/org.openhab.binding.openuv/README.md
Expand Up @@ -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 |
Expand Down
Expand Up @@ -22,5 +22,5 @@
*/
@NonNullByDefault
public class SafeExposureConfiguration {
public int index = -1;
public String index = "II";
}
Expand Up @@ -54,16 +54,14 @@
*/
@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) {
Expand All @@ -79,10 +77,10 @@ public void initialize() {
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
Expand All @@ -98,13 +96,13 @@ public void dispose() {
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");
}

Expand All @@ -113,11 +111,13 @@ private void initiateConnexion() {
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());
Expand All @@ -133,10 +133,10 @@ private void initiateConnexion() {

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;
Expand Down
Expand Up @@ -21,8 +21,6 @@
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;
Expand Down Expand Up @@ -174,7 +172,6 @@ public void dispose() {
uvMaxJob = null;
}

@SuppressWarnings("unchecked")
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (command instanceof RefreshType) {
Expand All @@ -184,8 +181,8 @@ public void handleCommand(ChannelUID channelUID, Command command) {
});
} 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);
}
Expand All @@ -208,7 +205,7 @@ private void updateChannel(ChannelUID channelUID, OpenUVResult openUVData) {
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()));
Expand All @@ -218,7 +215,7 @@ private void updateChannel(ChannelUID channelUID, OpenUVResult openUVData) {
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));
Expand All @@ -235,24 +232,14 @@ private void updateChannel(ChannelUID channelUID, OpenUVResult openUVData) {
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) {
Expand All @@ -261,7 +248,7 @@ private State asAlertLevel(int uv) {
return ALERT_ORANGE;
} else if (uv >= 3) {
return ALERT_YELLOW;
} else if (uv >= 1) {
} else if (uv > 0) {
return ALERT_GREEN;
}
return UnDefType.NULL;
Expand Down
Expand Up @@ -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;
}
}
Expand Up @@ -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
Expand All @@ -29,43 +36,68 @@
*/
@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() {
return ozone;
}

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;
}
}

This file was deleted.

@@ -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.

0 comments on commit 48dcb27

Please sign in to comment.