[Sagercaster] Reintroducing timestamp channel (#11665)
[Sagercaster] Reintroducing timestamp channel Signed-off-by: clinique <gael@lhopital.org>
This commit is contained in:
parent
13bae622ac
commit
4605edeb29
|
@ -6,7 +6,8 @@ The Sager Weathercaster is a scientific instrument for accurate prediction of th
|
||||||
|
|
||||||
* To operate, this binding will need to use channel values provided by other means (e.g. Weather Binding, Netatmo, a 1-Wire personal weather station...)
|
* To operate, this binding will need to use channel values provided by other means (e.g. Weather Binding, Netatmo, a 1-Wire personal weather station...)
|
||||||
|
|
||||||
* This binding buffers readings for some hours before producing weather forecasts(wind direction and sea level pressure). SagerWeatherCaster needs an observation period of minimum 6 hours.
|
* This binding buffers readings for some hours before producing weather forecasts(wind direction and sea level pressure).
|
||||||
|
SagerWeatherCaster needs an observation period of minimum 6 hours.
|
||||||
|
|
||||||
For these reasons, this binding is not a binding in the usual sense.
|
For these reasons, this binding is not a binding in the usual sense.
|
||||||
|
|
||||||
|
@ -24,9 +25,11 @@ The binding itself does not require any configuration.
|
||||||
|
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
|--------------------|----------|--------------------------------------------------------------------------|
|
|--------------------|----------|--------------------------------------------------------------------------|
|
||||||
| location | Location | Latitude and longitude of the desired weather forecast. |
|
| location (*) | Location | Latitude and longitude of the desired weather forecast. |
|
||||||
| observation-period | int | Minimum delay (in hours) before producing forecasts. Defaulted to 6. |
|
| observation-period | int | Minimum delay (in hours) before producing forecasts. Defaulted to 6. |
|
||||||
|
|
||||||
|
(*) Only latitude is used by the algorithm.
|
||||||
|
|
||||||
## Channels
|
## Channels
|
||||||
|
|
||||||
The binding will use some input channels, that can be configured directly with profiles (sample below).
|
The binding will use some input channels, that can be configured directly with profiles (sample below).
|
||||||
|
@ -41,6 +44,8 @@ The binding will use some input channels, that can be configured directly with p
|
||||||
| wind-speed-beaufort | input |Number | Wind speed expressed using the Beaufort scale |
|
| wind-speed-beaufort | input |Number | Wind speed expressed using the Beaufort scale |
|
||||||
| pressure | input |Number:Pressure | Sea level pressure |
|
| pressure | input |Number:Pressure | Sea level pressure |
|
||||||
| wind-angle | input |Number:Angle | Wind direction |
|
| wind-angle | input |Number:Angle | Wind direction |
|
||||||
|
| temperature | input |Number:Temperature | Outside temperature |
|
||||||
|
| timestamp | output |DateTime | Timestamp of the last forecast update |
|
||||||
| forecast | output |String | Description of the weather forecast |
|
| forecast | output |String | Description of the weather forecast |
|
||||||
| velocity | output |String | Description of the expected wind evolution |
|
| velocity | output |String | Description of the expected wind evolution |
|
||||||
| velocity-beaufort | output |Number | Expected wind evolution using the Beaufort scale |
|
| velocity-beaufort | output |Number | Expected wind evolution using the Beaufort scale |
|
||||||
|
|
|
@ -48,6 +48,8 @@ public class SagerCasterBindingConstants {
|
||||||
public static final String CHANNEL_WINDEVOLUTION = "wind-evolution";
|
public static final String CHANNEL_WINDEVOLUTION = "wind-evolution";
|
||||||
public static final String CHANNEL_PRESSURETREND = "pressure-trend";
|
public static final String CHANNEL_PRESSURETREND = "pressure-trend";
|
||||||
public static final String CHANNEL_TEMPERATURETREND = "temperature-trend";
|
public static final String CHANNEL_TEMPERATURETREND = "temperature-trend";
|
||||||
|
public static final String CHANNEL_TIMESTAMP = "timestamp";
|
||||||
|
|
||||||
// Input channel ids
|
// Input channel ids
|
||||||
public static final String CHANNEL_CLOUDINESS = "cloudiness";
|
public static final String CHANNEL_CLOUDINESS = "cloudiness";
|
||||||
public static final String CHANNEL_IS_RAINING = "is-raining";
|
public static final String CHANNEL_IS_RAINING = "is-raining";
|
||||||
|
|
|
@ -19,6 +19,7 @@ import java.util.Set;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import org.openhab.binding.sagercaster.internal.caster.SagerWeatherCaster;
|
||||||
import org.openhab.binding.sagercaster.internal.handler.SagerCasterHandler;
|
import org.openhab.binding.sagercaster.internal.handler.SagerCasterHandler;
|
||||||
import org.openhab.core.thing.Thing;
|
import org.openhab.core.thing.Thing;
|
||||||
import org.openhab.core.thing.ThingTypeUID;
|
import org.openhab.core.thing.ThingTypeUID;
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 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.sagercaster.internal.caster;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class holds the result of the SagerCaster algorithm
|
||||||
|
*
|
||||||
|
* @author Gaël L'hopital - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class SagerPrediction {
|
||||||
|
private final String prediction;
|
||||||
|
|
||||||
|
public SagerPrediction(String sagerCode) {
|
||||||
|
this.prediction = sagerCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSagerCode() {
|
||||||
|
return prediction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getForecast() {
|
||||||
|
return Character.toString(prediction.charAt(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getWindVelocity() {
|
||||||
|
return Character.toString(prediction.charAt(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getWindDirection() {
|
||||||
|
return Character.toString(prediction.charAt(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getWindDirection2() {
|
||||||
|
return prediction.length() > 3 ? Character.toString(prediction.charAt(3)) : SagerWeatherCaster.UNDEF;
|
||||||
|
}
|
||||||
|
}
|
|
@ -53,7 +53,7 @@
|
||||||
* 378 possible forecasts determined from 4996 dial codes.
|
* 378 possible forecasts determined from 4996 dial codes.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.openhab.binding.sagercaster.internal;
|
package org.openhab.binding.sagercaster.internal.caster;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
@ -76,6 +76,7 @@ import org.slf4j.LoggerFactory;
|
||||||
@Component(service = SagerWeatherCaster.class, scope = ServiceScope.SINGLETON)
|
@Component(service = SagerWeatherCaster.class, scope = ServiceScope.SINGLETON)
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class SagerWeatherCaster {
|
public class SagerWeatherCaster {
|
||||||
|
public final static String UNDEF = "-";
|
||||||
// Northern Polar Zone & Northern Tropical Zone
|
// Northern Polar Zone & Northern Tropical Zone
|
||||||
private final static String[] NPZDIRECTIONS = { "S", "SW", "W", "NW", "N", "NE", "E", "SE" };
|
private final static String[] NPZDIRECTIONS = { "S", "SW", "W", "NW", "N", "NE", "E", "SE" };
|
||||||
// Northern Temperate Zone
|
// Northern Temperate Zone
|
||||||
|
@ -88,7 +89,7 @@ public class SagerWeatherCaster {
|
||||||
private final Logger logger = LoggerFactory.getLogger(SagerWeatherCaster.class);
|
private final Logger logger = LoggerFactory.getLogger(SagerWeatherCaster.class);
|
||||||
private final Properties forecaster = new Properties();
|
private final Properties forecaster = new Properties();
|
||||||
|
|
||||||
private Optional<Prevision> prevision = Optional.empty();
|
private Optional<SagerPrediction> prevision = Optional.empty();
|
||||||
private String[] usedDirections = NTZDIRECTIONS; // Defaulted to Northern Zone
|
private String[] usedDirections = NTZDIRECTIONS; // Defaulted to Northern Zone
|
||||||
|
|
||||||
private int currentBearing = -1;
|
private int currentBearing = -1;
|
||||||
|
@ -238,7 +239,7 @@ public class SagerWeatherCaster {
|
||||||
|
|
||||||
private void updatePrediction() {
|
private void updatePrediction() {
|
||||||
int zWind = Arrays.asList(usedDirections).indexOf(getCompass());
|
int zWind = Arrays.asList(usedDirections).indexOf(getCompass());
|
||||||
String d1 = "-";
|
String d1 = UNDEF;
|
||||||
switch (zWind) {
|
switch (zWind) {
|
||||||
case 0:
|
case 0:
|
||||||
if (windEvolution == 3) {
|
if (windEvolution == 3) {
|
||||||
|
@ -319,39 +320,27 @@ public class SagerWeatherCaster {
|
||||||
}
|
}
|
||||||
String forecast = forecaster.getProperty(
|
String forecast = forecaster.getProperty(
|
||||||
d1 + String.valueOf(sagerPressure) + String.valueOf(pressureEvolution) + String.valueOf(nubes));
|
d1 + String.valueOf(sagerPressure) + String.valueOf(pressureEvolution) + String.valueOf(nubes));
|
||||||
prevision = (forecast != null) ? Optional.of(new Prevision(forecast)) : Optional.empty();
|
prevision = Optional.ofNullable(forecast != null ? new SagerPrediction(forecast) : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getForecast() {
|
public String getForecast() {
|
||||||
if (prevision.isPresent()) {
|
return prevision.map(p -> p.getForecast()).orElse(UNDEF);
|
||||||
char forecast = prevision.get().zForecast;
|
|
||||||
return Character.toString(forecast);
|
|
||||||
}
|
|
||||||
return "-";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getWindVelocity() {
|
public String getWindVelocity() {
|
||||||
if (prevision.isPresent()) {
|
return prevision.map(p -> p.getWindVelocity()).orElse(UNDEF);
|
||||||
char windVelocity = prevision.get().zWindVelocity;
|
|
||||||
return Character.toString(windVelocity);
|
|
||||||
}
|
|
||||||
return "-";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getWindDirection() {
|
public String getWindDirection() {
|
||||||
if (prevision.isPresent()) {
|
return prevision.map(p -> p.getWindDirection()).orElse(UNDEF);
|
||||||
int direction = prevision.get().zWindDirection;
|
|
||||||
return String.valueOf(direction);
|
|
||||||
}
|
|
||||||
return "-";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getWindDirection2() {
|
public String getWindDirection2() {
|
||||||
if (prevision.isPresent()) {
|
return prevision.map(p -> p.getWindDirection2()).orElse(UNDEF);
|
||||||
int direction = prevision.get().zWindDirection2;
|
|
||||||
return String.valueOf(direction);
|
|
||||||
}
|
}
|
||||||
return "-";
|
|
||||||
|
public String getSagerCode() {
|
||||||
|
return prevision.map(p -> p.getSagerCode()).orElse(UNDEF);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLatitude(double latitude) {
|
public void setLatitude(double latitude) {
|
||||||
|
@ -370,17 +359,31 @@ public class SagerWeatherCaster {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Prevision {
|
public int getPredictedBeaufort() {
|
||||||
public final char zForecast;
|
int result = currentBeaufort;
|
||||||
public final char zWindVelocity;
|
switch (getWindVelocity()) {
|
||||||
public final int zWindDirection;
|
case "N":
|
||||||
public final int zWindDirection2;
|
result += 1;
|
||||||
|
break;
|
||||||
public Prevision(String forecast) {
|
case "F":
|
||||||
zForecast = forecast.charAt(0);
|
result = 4;
|
||||||
zWindVelocity = forecast.charAt(1);
|
break;
|
||||||
zWindDirection = Character.getNumericValue(forecast.charAt(2));
|
case "S":
|
||||||
zWindDirection2 = (forecast.length() > 3) ? Character.getNumericValue(forecast.charAt(3)) : -1;
|
result = 6;
|
||||||
}
|
break;
|
||||||
|
case "G":
|
||||||
|
result = 8;
|
||||||
|
break;
|
||||||
|
case "W":
|
||||||
|
result = 10;
|
||||||
|
break;
|
||||||
|
case "H":
|
||||||
|
result = 12;
|
||||||
|
break;
|
||||||
|
case "D":
|
||||||
|
result -= 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -16,9 +16,9 @@ import static org.openhab.binding.sagercaster.internal.SagerCasterBindingConstan
|
||||||
import static org.openhab.core.library.unit.MetricPrefix.HECTO;
|
import static org.openhab.core.library.unit.MetricPrefix.HECTO;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import javax.measure.quantity.Angle;
|
import javax.measure.quantity.Angle;
|
||||||
|
@ -26,8 +26,9 @@ import javax.measure.quantity.Pressure;
|
||||||
import javax.measure.quantity.Temperature;
|
import javax.measure.quantity.Temperature;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.openhab.binding.sagercaster.internal.SagerWeatherCaster;
|
|
||||||
import org.openhab.binding.sagercaster.internal.WindDirectionStateDescriptionProvider;
|
import org.openhab.binding.sagercaster.internal.WindDirectionStateDescriptionProvider;
|
||||||
|
import org.openhab.binding.sagercaster.internal.caster.SagerWeatherCaster;
|
||||||
|
import org.openhab.core.library.types.DateTimeType;
|
||||||
import org.openhab.core.library.types.DecimalType;
|
import org.openhab.core.library.types.DecimalType;
|
||||||
import org.openhab.core.library.types.OnOffType;
|
import org.openhab.core.library.types.OnOffType;
|
||||||
import org.openhab.core.library.types.QuantityType;
|
import org.openhab.core.library.types.QuantityType;
|
||||||
|
@ -36,6 +37,7 @@ import org.openhab.core.library.unit.SIUnits;
|
||||||
import org.openhab.core.thing.ChannelUID;
|
import org.openhab.core.thing.ChannelUID;
|
||||||
import org.openhab.core.thing.Thing;
|
import org.openhab.core.thing.Thing;
|
||||||
import org.openhab.core.thing.ThingStatus;
|
import org.openhab.core.thing.ThingStatus;
|
||||||
|
import org.openhab.core.thing.ThingUID;
|
||||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||||
import org.openhab.core.types.Command;
|
import org.openhab.core.types.Command;
|
||||||
import org.openhab.core.types.RefreshType;
|
import org.openhab.core.types.RefreshType;
|
||||||
|
@ -58,11 +60,12 @@ public class SagerCasterHandler extends BaseThingHandler {
|
||||||
|
|
||||||
private final WindDirectionStateDescriptionProvider stateDescriptionProvider;
|
private final WindDirectionStateDescriptionProvider stateDescriptionProvider;
|
||||||
|
|
||||||
private final ExpiringMap<QuantityType<Pressure>> pressureCache = new ExpiringMap<>();
|
private final ExpiringMap<Double> pressureCache = new ExpiringMap<>();
|
||||||
private final ExpiringMap<QuantityType<Temperature>> temperatureCache = new ExpiringMap<>();
|
private final ExpiringMap<Double> temperatureCache = new ExpiringMap<>();
|
||||||
private final ExpiringMap<QuantityType<Angle>> bearingCache = new ExpiringMap<>();
|
private final ExpiringMap<Integer> bearingCache = new ExpiringMap<>();
|
||||||
|
|
||||||
private int currentTemp = 0;
|
private double currentTemp = 0;
|
||||||
|
private String currentSagerCode = SagerWeatherCaster.UNDEF;
|
||||||
|
|
||||||
public SagerCasterHandler(Thing thing, WindDirectionStateDescriptionProvider stateDescriptionProvider,
|
public SagerCasterHandler(Thing thing, WindDirectionStateDescriptionProvider stateDescriptionProvider,
|
||||||
SagerWeatherCaster sagerWeatherCaster) {
|
SagerWeatherCaster sagerWeatherCaster) {
|
||||||
|
@ -73,15 +76,17 @@ public class SagerCasterHandler extends BaseThingHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
String location = (String) getConfig().get(CONFIG_LOCATION);
|
|
||||||
int observationPeriod = ((BigDecimal) getConfig().get(CONFIG_PERIOD)).intValue();
|
int observationPeriod = ((BigDecimal) getConfig().get(CONFIG_PERIOD)).intValue();
|
||||||
String latitude = location.split(",")[0];
|
|
||||||
sagerWeatherCaster.setLatitude(Double.parseDouble(latitude));
|
|
||||||
long period = TimeUnit.HOURS.toMillis(observationPeriod);
|
long period = TimeUnit.HOURS.toMillis(observationPeriod);
|
||||||
pressureCache.setObservationPeriod(period);
|
pressureCache.setObservationPeriod(period);
|
||||||
bearingCache.setObservationPeriod(period);
|
bearingCache.setObservationPeriod(period);
|
||||||
temperatureCache.setObservationPeriod(period);
|
temperatureCache.setObservationPeriod(period);
|
||||||
|
|
||||||
|
String location = (String) getConfig().get(CONFIG_LOCATION);
|
||||||
|
String latitude = location.split(",")[0];
|
||||||
|
sagerWeatherCaster.setLatitude(Double.parseDouble(latitude));
|
||||||
defineWindDirectionStateDescriptions();
|
defineWindDirectionStateDescriptions();
|
||||||
|
|
||||||
updateStatus(ThingStatus.ONLINE);
|
updateStatus(ThingStatus.ONLINE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,10 +100,9 @@ public class SagerCasterHandler extends BaseThingHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
options.add(new StateOption("9", "Shifting / Variable winds"));
|
options.add(new StateOption("9", "Shifting / Variable winds"));
|
||||||
stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), GROUP_OUTPUT, CHANNEL_WINDFROM),
|
ThingUID thingUID = getThing().getUID();
|
||||||
options);
|
stateDescriptionProvider.setStateOptions(new ChannelUID(thingUID, GROUP_OUTPUT, CHANNEL_WINDFROM), options);
|
||||||
stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), GROUP_OUTPUT, CHANNEL_WINDTO),
|
stateDescriptionProvider.setStateOptions(new ChannelUID(thingUID, GROUP_OUTPUT, CHANNEL_WINDTO), options);
|
||||||
options);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -109,7 +113,7 @@ public class SagerCasterHandler extends BaseThingHandler {
|
||||||
String id = channelUID.getIdWithoutGroup();
|
String id = channelUID.getIdWithoutGroup();
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case CHANNEL_CLOUDINESS:
|
case CHANNEL_CLOUDINESS:
|
||||||
logger.debug("Octa cloud level changed, updating forecast");
|
logger.debug("Cloud level changed, updating forecast");
|
||||||
if (command instanceof QuantityType) {
|
if (command instanceof QuantityType) {
|
||||||
QuantityType<?> cloudiness = (QuantityType<?>) command;
|
QuantityType<?> cloudiness = (QuantityType<?>) command;
|
||||||
scheduler.submit(() -> {
|
scheduler.submit(() -> {
|
||||||
|
@ -127,26 +131,17 @@ public class SagerCasterHandler extends BaseThingHandler {
|
||||||
postNewForecast();
|
postNewForecast();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
logger.debug("Channel '{}' can only accept Switch type commands.", channelUID);
|
logger.debug("Channel '{}' accepts Switch commands.", channelUID);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CHANNEL_RAIN_QTTY:
|
case CHANNEL_RAIN_QTTY:
|
||||||
logger.debug("Rain status updated, updating forecast");
|
logger.debug("Rain status updated, updating forecast");
|
||||||
if (command instanceof QuantityType) {
|
if (command instanceof QuantityType) {
|
||||||
QuantityType<?> newQtty = (QuantityType<?>) command;
|
updateRain((QuantityType<?>) command);
|
||||||
scheduler.submit(() -> {
|
|
||||||
sagerWeatherCaster.setRaining(newQtty.doubleValue() > 0);
|
|
||||||
postNewForecast();
|
|
||||||
});
|
|
||||||
} else if (command instanceof DecimalType) {
|
} else if (command instanceof DecimalType) {
|
||||||
DecimalType newQtty = (DecimalType) command;
|
updateRain((DecimalType) command);
|
||||||
scheduler.submit(() -> {
|
|
||||||
sagerWeatherCaster.setRaining(newQtty.doubleValue() > 0);
|
|
||||||
postNewForecast();
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
logger.debug("Channel '{}' can accept Number, Number:Speed, Number:Length type commands.",
|
logger.debug("Channel '{}' accepts Number, Number:(Speed|Length) commands.", channelUID);
|
||||||
channelUID);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CHANNEL_WIND_SPEED:
|
case CHANNEL_WIND_SPEED:
|
||||||
|
@ -165,12 +160,13 @@ public class SagerCasterHandler extends BaseThingHandler {
|
||||||
logger.debug("Sea-level pressure updated, updating forecast");
|
logger.debug("Sea-level pressure updated, updating forecast");
|
||||||
if (command instanceof QuantityType) {
|
if (command instanceof QuantityType) {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
QuantityType<Pressure> newPressure = ((QuantityType<Pressure>) command)
|
QuantityType<Pressure> pressQtty = ((QuantityType<Pressure>) command)
|
||||||
.toUnit(HECTO(SIUnits.PASCAL));
|
.toUnit(HECTO(SIUnits.PASCAL));
|
||||||
if (newPressure != null) {
|
if (pressQtty != null) {
|
||||||
pressureCache.put(newPressure);
|
double newPressureValue = pressQtty.doubleValue();
|
||||||
pressureCache.getAgedValue().ifPresentOrElse(pressure -> scheduler.submit(() -> {
|
pressureCache.put(newPressureValue);
|
||||||
sagerWeatherCaster.setPressure(newPressure.doubleValue(), pressure.doubleValue());
|
pressureCache.getAgedValue().ifPresentOrElse(oldPressure -> scheduler.submit(() -> {
|
||||||
|
sagerWeatherCaster.setPressure(newPressureValue, oldPressure);
|
||||||
updateChannelString(GROUP_OUTPUT, CHANNEL_PRESSURETREND,
|
updateChannelString(GROUP_OUTPUT, CHANNEL_PRESSURETREND,
|
||||||
String.valueOf(sagerWeatherCaster.getPressureEvolution()));
|
String.valueOf(sagerWeatherCaster.getPressureEvolution()));
|
||||||
postNewForecast();
|
postNewForecast();
|
||||||
|
@ -182,14 +178,13 @@ public class SagerCasterHandler extends BaseThingHandler {
|
||||||
logger.debug("Temperature updated");
|
logger.debug("Temperature updated");
|
||||||
if (command instanceof QuantityType) {
|
if (command instanceof QuantityType) {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
QuantityType<Temperature> newTemperature = ((QuantityType<Temperature>) command)
|
QuantityType<Temperature> tempQtty = ((QuantityType<Temperature>) command)
|
||||||
.toUnit(SIUnits.CELSIUS);
|
.toUnit(SIUnits.CELSIUS);
|
||||||
if (newTemperature != null) {
|
if (tempQtty != null) {
|
||||||
temperatureCache.put(newTemperature);
|
currentTemp = tempQtty.doubleValue();
|
||||||
currentTemp = newTemperature.intValue();
|
temperatureCache.put(currentTemp);
|
||||||
Optional<QuantityType<Temperature>> agedTemperature = temperatureCache.getAgedValue();
|
temperatureCache.getAgedValue().ifPresent(oldTemperature -> {
|
||||||
agedTemperature.ifPresent(temperature -> {
|
double delta = currentTemp - oldTemperature;
|
||||||
double delta = newTemperature.doubleValue() - temperature.doubleValue();
|
|
||||||
String trend = (delta > 3) ? "1"
|
String trend = (delta > 3) ? "1"
|
||||||
: (delta > 0.3) ? "2" : (delta > -0.3) ? "3" : (delta > -3) ? "4" : "5";
|
: (delta > 0.3) ? "2" : (delta > -0.3) ? "3" : (delta > -3) ? "4" : "5";
|
||||||
updateChannelString(GROUP_OUTPUT, CHANNEL_TEMPERATURETREND, trend);
|
updateChannelString(GROUP_OUTPUT, CHANNEL_TEMPERATURETREND, trend);
|
||||||
|
@ -201,12 +196,12 @@ public class SagerCasterHandler extends BaseThingHandler {
|
||||||
logger.debug("Updated wind direction, updating forecast");
|
logger.debug("Updated wind direction, updating forecast");
|
||||||
if (command instanceof QuantityType) {
|
if (command instanceof QuantityType) {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
QuantityType<Angle> newAngle = (QuantityType<Angle>) command;
|
QuantityType<Angle> angleQtty = (QuantityType<Angle>) command;
|
||||||
bearingCache.put(newAngle);
|
int newAngleValue = angleQtty.intValue();
|
||||||
Optional<QuantityType<Angle>> agedAngle = bearingCache.getAgedValue();
|
bearingCache.put(newAngleValue);
|
||||||
agedAngle.ifPresent(angle -> {
|
bearingCache.getAgedValue().ifPresent(oldAngle -> {
|
||||||
scheduler.submit(() -> {
|
scheduler.submit(() -> {
|
||||||
sagerWeatherCaster.setBearing(newAngle.intValue(), angle.intValue());
|
sagerWeatherCaster.setBearing(newAngleValue, oldAngle);
|
||||||
updateChannelString(GROUP_OUTPUT, CHANNEL_WINDEVOLUTION,
|
updateChannelString(GROUP_OUTPUT, CHANNEL_WINDEVOLUTION,
|
||||||
String.valueOf(sagerWeatherCaster.getWindEvolution()));
|
String.valueOf(sagerWeatherCaster.getWindEvolution()));
|
||||||
postNewForecast();
|
postNewForecast();
|
||||||
|
@ -220,7 +215,19 @@ public class SagerCasterHandler extends BaseThingHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateRain(Number newQtty) {
|
||||||
|
scheduler.submit(() -> {
|
||||||
|
sagerWeatherCaster.setRaining(newQtty.doubleValue() > 0);
|
||||||
|
postNewForecast();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void postNewForecast() {
|
private void postNewForecast() {
|
||||||
|
String newSagerCode = sagerWeatherCaster.getSagerCode();
|
||||||
|
if (!newSagerCode.equals(currentSagerCode)) {
|
||||||
|
logger.debug("Sager prediction changed to {}", newSagerCode);
|
||||||
|
currentSagerCode = newSagerCode;
|
||||||
|
updateChannelTimeStamp(GROUP_OUTPUT, CHANNEL_TIMESTAMP, ZonedDateTime.now());
|
||||||
String forecast = sagerWeatherCaster.getForecast();
|
String forecast = sagerWeatherCaster.getForecast();
|
||||||
// Sharpens forecast if current temp is below 2 degrees, likely to be flurries rather than shower
|
// Sharpens forecast if current temp is below 2 degrees, likely to be flurries rather than shower
|
||||||
forecast += SHOWERS.contains(forecast) ? (currentTemp > 2) ? "1" : "2" : "";
|
forecast += SHOWERS.contains(forecast) ? (currentTemp > 2) ? "1" : "2" : "";
|
||||||
|
@ -228,34 +235,16 @@ public class SagerCasterHandler extends BaseThingHandler {
|
||||||
updateChannelString(GROUP_OUTPUT, CHANNEL_FORECAST, forecast);
|
updateChannelString(GROUP_OUTPUT, CHANNEL_FORECAST, forecast);
|
||||||
updateChannelString(GROUP_OUTPUT, CHANNEL_WINDFROM, sagerWeatherCaster.getWindDirection());
|
updateChannelString(GROUP_OUTPUT, CHANNEL_WINDFROM, sagerWeatherCaster.getWindDirection());
|
||||||
updateChannelString(GROUP_OUTPUT, CHANNEL_WINDTO, sagerWeatherCaster.getWindDirection2());
|
updateChannelString(GROUP_OUTPUT, CHANNEL_WINDTO, sagerWeatherCaster.getWindDirection2());
|
||||||
|
updateChannelString(GROUP_OUTPUT, CHANNEL_VELOCITY, sagerWeatherCaster.getWindVelocity());
|
||||||
String velocity = sagerWeatherCaster.getWindVelocity();
|
updateChannelDecimal(GROUP_OUTPUT, CHANNEL_VELOCITY_BEAUFORT, sagerWeatherCaster.getPredictedBeaufort());
|
||||||
updateChannelString(GROUP_OUTPUT, CHANNEL_VELOCITY, velocity);
|
}
|
||||||
int predictedBeaufort = sagerWeatherCaster.getBeaufort();
|
}
|
||||||
switch (velocity) {
|
|
||||||
case "N":
|
private void updateChannelTimeStamp(String group, String channelId, ZonedDateTime zonedDateTime) {
|
||||||
predictedBeaufort += 1;
|
ChannelUID id = new ChannelUID(getThing().getUID(), group, channelId);
|
||||||
break;
|
if (isLinked(id)) {
|
||||||
case "F":
|
updateState(id, new DateTimeType(zonedDateTime));
|
||||||
predictedBeaufort = 4;
|
|
||||||
break;
|
|
||||||
case "S":
|
|
||||||
predictedBeaufort = 6;
|
|
||||||
break;
|
|
||||||
case "G":
|
|
||||||
predictedBeaufort = 8;
|
|
||||||
break;
|
|
||||||
case "W":
|
|
||||||
predictedBeaufort = 10;
|
|
||||||
break;
|
|
||||||
case "H":
|
|
||||||
predictedBeaufort = 12;
|
|
||||||
break;
|
|
||||||
case "D":
|
|
||||||
predictedBeaufort -= 1;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
updateChannelDecimal(GROUP_OUTPUT, CHANNEL_VELOCITY_BEAUFORT, predictedBeaufort);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateChannelString(String group, String channelId, String value) {
|
private void updateChannelString(String group, String channelId, String value) {
|
||||||
|
|
|
@ -43,6 +43,8 @@ rainingDescription = Is it currently raining ?
|
||||||
beaufortLabel = Beaufort
|
beaufortLabel = Beaufort
|
||||||
beaufortDescription = Wind speed using Beaufort Scale
|
beaufortDescription = Wind speed using Beaufort Scale
|
||||||
pressureDescription = Barometric pressure at sea level.
|
pressureDescription = Barometric pressure at sea level.
|
||||||
|
timestampChannelLabel = Timestamp
|
||||||
|
timestampChannelDescription = Timestamp of the last weather forecast update.
|
||||||
|
|
||||||
# channel options
|
# channel options
|
||||||
forecast0 = Not enough historic data to study pressure evolution, wait a bit ...
|
forecast0 = Not enough historic data to study pressure evolution, wait a bit ...
|
||||||
|
@ -52,33 +54,33 @@ forecastC = Fair and cooler
|
||||||
forecastD = Unsettled
|
forecastD = Unsettled
|
||||||
forecastE = Unsettled and warmer
|
forecastE = Unsettled and warmer
|
||||||
forecastF = Unsettled and cooler
|
forecastF = Unsettled and cooler
|
||||||
forecastG = Increasing cloudiness or overcast followed by Precipitation or showers/Flurries
|
forecastG = Increasing cloudiness or overcast followed by precipitation or showers/flurries
|
||||||
forecastG1 = Increasing cloudiness or overcast followed by Precipitation or showers
|
forecastG1 = Increasing cloudiness or overcast followed by precipitation or showers
|
||||||
forecastG2 = Increasing cloudiness or overcast followed by Precipitation or Flurries
|
forecastG2 = Increasing cloudiness or overcast followed by precipitation or flurries
|
||||||
forecastH = Increasing cloudiness or overcast followed by Precipitation or showers and warmer
|
forecastH = Increasing cloudiness or overcast followed by precipitation or showers and warmer
|
||||||
forecastJ = Showers
|
forecastJ = Showers
|
||||||
forecastK = Showers/Flurries and warmer
|
forecastK = Showers/flurries and warmer
|
||||||
forecastK1 = Showers and warmer
|
forecastK1 = Showers and warmer
|
||||||
forecastK2 = Flurries and warmer
|
forecastK2 = Flurries and warmer
|
||||||
forecastL = Showers/Flurries and cooler
|
forecastL = Showers/flurries and cooler
|
||||||
forecastL1 = Showers and cooler
|
forecastL1 = Showers and cooler
|
||||||
forecastL2 = Flurries and cooler
|
forecastL2 = Flurries and cooler
|
||||||
forecastM = Precipitation
|
forecastM = Precipitation
|
||||||
forecastN = Precipitation and warmer
|
forecastN = Precipitation and warmer
|
||||||
forecastP = Precipitation and turning cooler; then improvement likely in 24 hours
|
forecastP = Precipitation and turning cooler; then improvement likely in 24 hours
|
||||||
forecastR = Precipitation or showers/Flurries followed by improvement (within 12 hours)
|
forecastR = Precipitation or showers/flurries followed by improvement (within 12 hours)
|
||||||
forecastR1 = Precipitation or showers followed by improvement (within 12 hours)
|
forecastR1 = Precipitation or showers followed by improvement (within 12 hours)
|
||||||
forecastR2 = Precipitation or flurries followed by improvement (within 12 hours)
|
forecastR2 = Precipitation or flurries followed by improvement (within 12 hours)
|
||||||
forecastS = Precipitation or showers/Flurries followed by improvement (within 12 hours) and becoming cooler
|
forecastS = Precipitation or showers/flurries followed by improvement (within 12 hours) and becoming cooler
|
||||||
forecastS1 = Precipitation or showers followed by improvement (within 12 hours) and becoming cooler
|
forecastS1 = Precipitation or showers followed by improvement (within 12 hours) and becoming cooler
|
||||||
forecastS2 = Precipitation or flurries followed by improvement (within 12 hours) and becoming cooler
|
forecastS2 = Precipitation or flurries followed by improvement (within 12 hours) and becoming cooler
|
||||||
forecastT = Precipitation or showers/Flurries followed by improvement early in period (within 6 hours)
|
forecastT = Precipitation or showers/flurries followed by improvement early in period (within 6 hours)
|
||||||
forecastT1 = Precipitation or showers followed by improvement early in period (within 6 hours)
|
forecastT1 = Precipitation or showers followed by improvement early in period (within 6 hours)
|
||||||
forecastT2 = Precipitation or flurries followed by improvement early in period (within 6 hours)
|
forecastT2 = Precipitation or flurries followed by improvement early in period (within 6 hours)
|
||||||
forecastU = Precipitation or showers/Flurries by improvement early in period (within 6 hours) and becoming cooler
|
forecastU = Precipitation or showers/flurries by improvement early in period (within 6 hours) and becoming cooler
|
||||||
forecastU1 = Precipitation or showers by improvement early in period (within 6 hours) and becoming cooler
|
forecastU1 = Precipitation or showers by improvement early in period (within 6 hours) and becoming cooler
|
||||||
forecastU2 = Precipitation or flurries by improvement early in period (within 6 hours) and becoming cooler
|
forecastU2 = Precipitation or flurries by improvement early in period (within 6 hours) and becoming cooler
|
||||||
forecastW = Precipitation or showers/Flurries followed by fair early in period (within 6 hours) and becoming cooler
|
forecastW = Precipitation or showers/flurries followed by fair early in period (within 6 hours) and becoming cooler
|
||||||
forecastW1 = Precipitation or showers followed by fair early in period (within 6 hours) and becoming cooler
|
forecastW1 = Precipitation or showers followed by fair early in period (within 6 hours) and becoming cooler
|
||||||
forecastW2 = Precipitation or flurries followed by fair early in period (within 6 hours) and becoming cooler
|
forecastW2 = Precipitation or flurries followed by fair early in period (within 6 hours) and becoming cooler
|
||||||
forecastX = Unsettled followed by fair
|
forecastX = Unsettled followed by fair
|
||||||
|
|
|
@ -43,6 +43,8 @@ rainingDescription = Pleut-il actuellement ?
|
||||||
beaufortLabel = Beaufort
|
beaufortLabel = Beaufort
|
||||||
beaufortDescription = Force du vent mesurée sur l'échelle Beaufort
|
beaufortDescription = Force du vent mesurée sur l'échelle Beaufort
|
||||||
pressureDescription = Pression barométrique au niveau de la mer.
|
pressureDescription = Pression barométrique au niveau de la mer.
|
||||||
|
timestampChannelLabel = Horodatage
|
||||||
|
timestampChannelDescription = Horodatage de la dernière mise à jour de la prévision météo.
|
||||||
|
|
||||||
# channel options
|
# channel options
|
||||||
forecast0 = Patientez encore un peu pour une prédiction
|
forecast0 = Patientez encore un peu pour une prédiction
|
||||||
|
|
|
@ -72,6 +72,7 @@
|
||||||
<label>@text/tempTrendLabel</label>
|
<label>@text/tempTrendLabel</label>
|
||||||
<description>@text/tempTrendDescription</description>
|
<description>@text/tempTrendDescription</description>
|
||||||
</channel>
|
</channel>
|
||||||
|
<channel id="timestamp" typeId="timestamp"/>
|
||||||
</channels>
|
</channels>
|
||||||
</channel-group-type>
|
</channel-group-type>
|
||||||
|
|
||||||
|
@ -163,6 +164,7 @@
|
||||||
<item-type>String</item-type>
|
<item-type>String</item-type>
|
||||||
<label>@text/trendLabel</label>
|
<label>@text/trendLabel</label>
|
||||||
<description>@text/trendDescription</description>
|
<description>@text/trendDescription</description>
|
||||||
|
<category>Line</category>
|
||||||
<state readOnly="true" pattern="%s">
|
<state readOnly="true" pattern="%s">
|
||||||
<options>
|
<options>
|
||||||
<option value="1">@text/trend1</option>
|
<option value="1">@text/trend1</option>
|
||||||
|
@ -174,19 +176,23 @@
|
||||||
</state>
|
</state>
|
||||||
</channel-type>
|
</channel-type>
|
||||||
|
|
||||||
<channel-type id="timestamp" advanced="true">
|
<channel-type id="timestamp">
|
||||||
<item-type>DateTime</item-type>
|
<item-type>DateTime</item-type>
|
||||||
<label>@text/timestampLabel</label>
|
<label>@text/timestampChannelLabel</label>
|
||||||
<description>@text/timestampDescription</description>
|
<description>@text/timestampChannelDescription</description>
|
||||||
<category>Observation time</category>
|
<category>Time</category>
|
||||||
<state readOnly="true"></state>
|
<tags>
|
||||||
|
<tag>Status</tag>
|
||||||
|
<tag>Timestamp</tag>
|
||||||
|
</tags>
|
||||||
|
<state readOnly="true"/>
|
||||||
</channel-type>
|
</channel-type>
|
||||||
|
|
||||||
<channel-type id="cloudiness">
|
<channel-type id="cloudiness">
|
||||||
<item-type>Number:Dimensionless</item-type>
|
<item-type>Number:Dimensionless</item-type>
|
||||||
<label>@text/cloudinessLabel</label>
|
<label>@text/cloudinessLabel</label>
|
||||||
<description>@text/cloudinessDescription</description>
|
<description>@text/cloudinessDescription</description>
|
||||||
<category>Clouds</category>
|
<category>Sun_Clouds</category>
|
||||||
<state min="0" max="100" pattern="%d %%"/>
|
<state min="0" max="100" pattern="%d %%"/>
|
||||||
</channel-type>
|
</channel-type>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue