[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 <gael@lhopital.org>
This commit is contained in:
parent
b27ddbe9fc
commit
48dcb27a61
@ -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 |
|
||||
|
||||
@ -22,5 +22,5 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SafeExposureConfiguration {
|
||||
public int index = -1;
|
||||
public String index = "II";
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<FitzpatrickType, @Nullable Integer> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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.
|
||||
@ -67,14 +67,14 @@
|
||||
<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">
|
||||
@ -102,37 +102,39 @@
|
||||
|
||||
<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>
|
||||
@ -140,7 +142,8 @@
|
||||
<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>
|
||||
|
||||
@ -154,6 +157,7 @@
|
||||
<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>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user