Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[OpenUV] Issue when UV index < 1 #9198

Merged
merged 3 commits into from Dec 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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.