[synopanalyzer] Incorrect octa reported (#12541)
* Some stations does not report octa dimension, thus leading the binding to incorrect values. Enhanced discovery process Code enhancements SAT corrections Enhanced Exception catching. Signed-off-by: clinique <gael@lhopital.org>
This commit is contained in:
parent
3520621c1b
commit
94301eee8c
|
@ -12,7 +12,9 @@ There is exactly one supported thing, which represents a Synop message. It has t
|
|||
|
||||
## Discovery
|
||||
|
||||
If a system location is set, the nearest availabble Synop station be automatically discovered for this location.
|
||||
If a system location is set, the nearest available Synop station be automatically discovered for this location.
|
||||
The search radius will expand at each successive scan.
|
||||
|
||||
|
||||
## Thing Configuration
|
||||
|
||||
|
@ -26,7 +28,7 @@ The weather information that is retrieved is available as these channels:
|
|||
|
||||
| Channel Type ID | Item Type | Description |
|
||||
|-----------------------|--------------------|--------------------------------------------|
|
||||
| temperature | Number:Temperature | Current temperature |
|
||||
| temperature | Number:Temperature | Current outdoor temperature |
|
||||
| pressure | Number:Pressure | Current pressure |
|
||||
| wind-speed | Number:Speed | Current wind speed |
|
||||
| wind-speed-beaufort | Number | Wind speed according to Beaufort scale |
|
||||
|
|
|
@ -25,14 +25,13 @@ import org.openhab.core.library.unit.Units;
|
|||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link SynopAnalyzerBinding} class defines common constants, which are
|
||||
* used across the whole binding.
|
||||
* The {@link SynopAnalyzerBinding} class defines common constants used across the whole binding.
|
||||
*
|
||||
* @author Gaël L'hopital - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SynopAnalyzerBindingConstants {
|
||||
public static final String BINDING_ID = "synopanalyzer";
|
||||
private static final String BINDING_ID = "synopanalyzer";
|
||||
|
||||
// List of all Thing Type UIDs
|
||||
public static final ThingTypeUID THING_SYNOP = new ThingTypeUID(BINDING_ID, "synopanalyzer");
|
||||
|
|
|
@ -14,38 +14,25 @@ package org.openhab.binding.synopanalyzer.internal;
|
|||
|
||||
import static org.openhab.binding.synopanalyzer.internal.SynopAnalyzerBindingConstants.THING_SYNOP;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Hashtable;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.synopanalyzer.internal.discovery.SynopAnalyzerDiscoveryService;
|
||||
import org.openhab.binding.synopanalyzer.internal.handler.SynopAnalyzerHandler;
|
||||
import org.openhab.binding.synopanalyzer.internal.synop.StationDB;
|
||||
import org.openhab.core.config.discovery.DiscoveryService;
|
||||
import org.openhab.binding.synopanalyzer.internal.stationdb.Station;
|
||||
import org.openhab.binding.synopanalyzer.internal.stationdb.StationDbService;
|
||||
import org.openhab.core.i18n.LocationProvider;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerFactory;
|
||||
import org.osgi.framework.ServiceRegistration;
|
||||
import org.osgi.service.component.ComponentContext;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
/**
|
||||
* The {@link SynopAnalyzerHandlerFactory} is responsible for creating things and thing
|
||||
* handlers.
|
||||
* The {@link SynopAnalyzerHandlerFactory} is responsible for creating things and thing handlers.
|
||||
*
|
||||
* @author Gaël L'hopital - Initial contribution
|
||||
*/
|
||||
|
@ -53,15 +40,14 @@ import com.google.gson.Gson;
|
|||
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.synopanalyzer")
|
||||
@NonNullByDefault
|
||||
public class SynopAnalyzerHandlerFactory extends BaseThingHandlerFactory {
|
||||
private final Logger logger = LoggerFactory.getLogger(SynopAnalyzerHandlerFactory.class);
|
||||
private final LocationProvider locationProvider;
|
||||
private final Gson gson = new Gson();
|
||||
private @Nullable StationDB stationDB;
|
||||
private @Nullable ServiceRegistration<?> serviceReg;
|
||||
private final List<Station> stationDB;
|
||||
|
||||
@Activate
|
||||
public SynopAnalyzerHandlerFactory(@Reference LocationProvider locationProvider) {
|
||||
public SynopAnalyzerHandlerFactory(@Reference StationDbService stationDBService,
|
||||
@Reference LocationProvider locationProvider) {
|
||||
this.locationProvider = locationProvider;
|
||||
this.stationDB = stationDBService.getStations();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -74,40 +60,4 @@ public class SynopAnalyzerHandlerFactory extends BaseThingHandlerFactory {
|
|||
return supportsThingType(thing.getThingTypeUID()) ? new SynopAnalyzerHandler(thing, locationProvider, stationDB)
|
||||
: null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void activate(ComponentContext componentContext) {
|
||||
super.activate(componentContext);
|
||||
|
||||
try (InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("/db/stations.json");
|
||||
Reader reader = new InputStreamReader(is, StandardCharsets.UTF_8);) {
|
||||
|
||||
StationDB stations = gson.fromJson(reader, StationDB.class);
|
||||
registerDiscoveryService(stations);
|
||||
this.stationDB = stations;
|
||||
logger.debug("Discovery service for Synop Stations registered.");
|
||||
} catch (IOException e) {
|
||||
logger.warn("Unable to read synop stations database");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deactivate(ComponentContext componentContext) {
|
||||
unregisterDiscoveryService();
|
||||
super.deactivate(componentContext);
|
||||
}
|
||||
|
||||
private void registerDiscoveryService(StationDB stations) {
|
||||
SynopAnalyzerDiscoveryService discoveryService = new SynopAnalyzerDiscoveryService(stations, locationProvider);
|
||||
|
||||
serviceReg = bundleContext.registerService(DiscoveryService.class.getName(), discoveryService,
|
||||
new Hashtable<>());
|
||||
}
|
||||
|
||||
private void unregisterDiscoveryService() {
|
||||
if (serviceReg != null) {
|
||||
serviceReg.unregister();
|
||||
serviceReg = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,11 +13,9 @@
|
|||
package org.openhab.binding.synopanalyzer.internal.config;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.synopanalyzer.internal.handler.SynopAnalyzerHandler;
|
||||
|
||||
/**
|
||||
* The {@link SynopAnalyzerConfiguration} is responsible for holding configuration
|
||||
* informations needed for {@link SynopAnalyzerHandler}
|
||||
* The {@link SynopAnalyzerConfiguration} holds configuration informations needed for the Synop thing
|
||||
*
|
||||
* @author Gaël L'hopital - Initial contribution
|
||||
*/
|
||||
|
|
|
@ -14,49 +14,50 @@ package org.openhab.binding.synopanalyzer.internal.discovery;
|
|||
|
||||
import static org.openhab.binding.synopanalyzer.internal.SynopAnalyzerBindingConstants.THING_SYNOP;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.synopanalyzer.internal.config.SynopAnalyzerConfiguration;
|
||||
import org.openhab.binding.synopanalyzer.internal.synop.StationDB;
|
||||
import org.openhab.binding.synopanalyzer.internal.synop.StationDB.Station;
|
||||
import org.openhab.binding.synopanalyzer.internal.stationdb.Station;
|
||||
import org.openhab.binding.synopanalyzer.internal.stationdb.StationDbService;
|
||||
import org.openhab.core.config.discovery.AbstractDiscoveryService;
|
||||
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
||||
import org.openhab.core.config.discovery.DiscoveryService;
|
||||
import org.openhab.core.i18n.LocationProvider;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.PointType;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link SynopAnalyzerDiscoveryService} creates things based on the configured location.
|
||||
* The {@link SynopAnalyzerDiscoveryService} discovers synop stations based on the configured location.
|
||||
*
|
||||
* @author Gaël L'hopital - Initial Contribution
|
||||
*/
|
||||
@Component(service = DiscoveryService.class)
|
||||
@NonNullByDefault
|
||||
public class SynopAnalyzerDiscoveryService extends AbstractDiscoveryService {
|
||||
private static final int DISCOVER_TIMEOUT_SECONDS = 5;
|
||||
private static final int DISCOVER_TIMEOUT_SECONDS = 2;
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(SynopAnalyzerDiscoveryService.class);
|
||||
private final Map<Integer, Double> distances = new HashMap<>();
|
||||
private final LocationProvider locationProvider;
|
||||
private final StationDB stationDB;
|
||||
private final List<Station> stations;
|
||||
private double radius = 0;
|
||||
|
||||
/**
|
||||
* Creates a SynopAnalyzerDiscoveryService with enabled autostart.
|
||||
*
|
||||
*/
|
||||
public SynopAnalyzerDiscoveryService(StationDB stationDB, LocationProvider locationProvider) {
|
||||
super(Collections.singleton(THING_SYNOP), DISCOVER_TIMEOUT_SECONDS);
|
||||
@Activate
|
||||
public SynopAnalyzerDiscoveryService(@Reference StationDbService dBService,
|
||||
@Reference LocationProvider locationProvider) {
|
||||
super(Set.of(THING_SYNOP), DISCOVER_TIMEOUT_SECONDS);
|
||||
this.locationProvider = locationProvider;
|
||||
this.stationDB = stationDB;
|
||||
this.stations = dBService.getStations();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -71,23 +72,29 @@ public class SynopAnalyzerDiscoveryService extends AbstractDiscoveryService {
|
|||
}
|
||||
|
||||
public void createResults(PointType serverLocation) {
|
||||
distances.clear();
|
||||
Map<Double, Station> distances = new TreeMap<>();
|
||||
|
||||
stationDB.stations.forEach(s -> {
|
||||
PointType stationLocation = new PointType(s.getLocation());
|
||||
DecimalType distance = serverLocation.distanceFrom(stationLocation);
|
||||
distances.put(s.idOmm, distance.doubleValue());
|
||||
stations.forEach(station -> {
|
||||
PointType stationLocation = new PointType(station.getLocation());
|
||||
double distance = serverLocation.distanceFrom(stationLocation).doubleValue();
|
||||
if (distance > radius) {
|
||||
distances.put(distance, station);
|
||||
}
|
||||
});
|
||||
|
||||
Map<Integer, Double> result = distances.entrySet().stream()
|
||||
.sorted(Map.Entry.comparingByValue(Comparator.naturalOrder())).collect(Collectors.toMap(
|
||||
Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -> oldValue, LinkedHashMap::new));
|
||||
Iterator<Entry<Double, Station>> stationIterator = distances.entrySet().iterator();
|
||||
if (stationIterator.hasNext()) {
|
||||
Entry<Double, Station> nearest = stationIterator.next();
|
||||
Station station = nearest.getValue();
|
||||
radius = nearest.getKey();
|
||||
|
||||
Integer nearestId = result.entrySet().iterator().next().getKey();
|
||||
Optional<Station> station = stationDB.stations.stream().filter(s -> s.idOmm == nearestId).findFirst();
|
||||
thingDiscovered(DiscoveryResultBuilder.create(new ThingUID(THING_SYNOP, nearestId.toString()))
|
||||
.withLabel(String.format("Synop : %s", station.get().usualName))
|
||||
.withProperty(SynopAnalyzerConfiguration.STATION_ID, nearestId)
|
||||
.withRepresentationProperty(SynopAnalyzerConfiguration.STATION_ID).build());
|
||||
thingDiscovered(DiscoveryResultBuilder.create(new ThingUID(THING_SYNOP, Integer.toString(station.idOmm)))
|
||||
.withLabel(String.format("Synop : %s", station.usualName))
|
||||
.withProperty(SynopAnalyzerConfiguration.STATION_ID, station.idOmm)
|
||||
.withRepresentationProperty(SynopAnalyzerConfiguration.STATION_ID).build());
|
||||
} else {
|
||||
logger.info("No Synop station available at a radius higher than {} m - resetting to 0 m", radius);
|
||||
radius = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,8 +33,8 @@ import javax.ws.rs.HttpMethod;
|
|||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.synopanalyzer.internal.config.SynopAnalyzerConfiguration;
|
||||
import org.openhab.binding.synopanalyzer.internal.stationdb.Station;
|
||||
import org.openhab.binding.synopanalyzer.internal.synop.Overcast;
|
||||
import org.openhab.binding.synopanalyzer.internal.synop.StationDB;
|
||||
import org.openhab.binding.synopanalyzer.internal.synop.Synop;
|
||||
import org.openhab.binding.synopanalyzer.internal.synop.SynopLand;
|
||||
import org.openhab.binding.synopanalyzer.internal.synop.SynopMobile;
|
||||
|
@ -51,6 +51,7 @@ import org.openhab.core.library.unit.SIUnits;
|
|||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
|
@ -75,16 +76,16 @@ public class SynopAnalyzerHandler extends BaseThingHandler {
|
|||
private static final double OCTA_MAX = 8.0;
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(SynopAnalyzerHandler.class);
|
||||
|
||||
private @Nullable ScheduledFuture<?> executionJob;
|
||||
private @NonNullByDefault({}) String formattedStationId;
|
||||
private final LocationProvider locationProvider;
|
||||
private final @Nullable StationDB stationDB;
|
||||
private final List<Station> stations;
|
||||
|
||||
public SynopAnalyzerHandler(Thing thing, LocationProvider locationProvider, @Nullable StationDB stationDB) {
|
||||
private Optional<ScheduledFuture<?>> refreshJob = Optional.empty();
|
||||
private @NonNullByDefault({}) String formattedStationId;
|
||||
|
||||
public SynopAnalyzerHandler(Thing thing, LocationProvider locationProvider, List<Station> stations) {
|
||||
super(thing);
|
||||
this.locationProvider = locationProvider;
|
||||
this.stationDB = stationDB;
|
||||
this.stations = stations;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -94,26 +95,23 @@ public class SynopAnalyzerHandler extends BaseThingHandler {
|
|||
logger.info("Scheduling Synop update thread to run every {} minute for Station '{}'",
|
||||
configuration.refreshInterval, formattedStationId);
|
||||
|
||||
StationDB stations = stationDB;
|
||||
if (thing.getProperties().isEmpty() && stations != null) {
|
||||
discoverAttributes(stations, configuration.stationId);
|
||||
if (thing.getProperties().isEmpty()) {
|
||||
discoverAttributes(configuration.stationId, locationProvider.getLocation());
|
||||
}
|
||||
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
|
||||
executionJob = scheduler.scheduleWithFixedDelay(this::updateSynopChannels, 0, configuration.refreshInterval,
|
||||
TimeUnit.MINUTES);
|
||||
refreshJob = Optional.of(scheduler.scheduleWithFixedDelay(this::updateChannels, 0,
|
||||
configuration.refreshInterval, TimeUnit.MINUTES));
|
||||
}
|
||||
|
||||
protected void discoverAttributes(StationDB stations, int stationId) {
|
||||
stations.stations.stream().filter(s -> stationId == s.idOmm).findFirst().ifPresent(s -> {
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
properties.put("Usual name", s.usualName);
|
||||
properties.put("Location", s.getLocation());
|
||||
private void discoverAttributes(int stationId, @Nullable PointType serverLocation) {
|
||||
stations.stream().filter(s -> stationId == s.idOmm).findFirst().ifPresent(station -> {
|
||||
Map<String, String> properties = new HashMap<>(
|
||||
Map.of("Usual name", station.usualName, "Location", station.getLocation()));
|
||||
|
||||
PointType stationLocation = new PointType(s.getLocation());
|
||||
PointType serverLocation = locationProvider.getLocation();
|
||||
if (serverLocation != null) {
|
||||
PointType stationLocation = new PointType(station.getLocation());
|
||||
DecimalType distance = serverLocation.distanceFrom(stationLocation);
|
||||
|
||||
properties.put("Distance", new QuantityType<>(distance, SIUnits.METRE).toString());
|
||||
|
@ -149,33 +147,35 @@ public class SynopAnalyzerHandler extends BaseThingHandler {
|
|||
return Optional.empty();
|
||||
}
|
||||
|
||||
private void updateSynopChannels() {
|
||||
private void updateChannels() {
|
||||
logger.debug("Updating device channels");
|
||||
|
||||
Optional<Synop> synop = getLastAvailableSynop();
|
||||
updateStatus(synop.isPresent() ? ThingStatus.ONLINE : ThingStatus.OFFLINE);
|
||||
synop.ifPresent(theSynop -> {
|
||||
getLastAvailableSynop().ifPresentOrElse(synop -> {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
getThing().getChannels().forEach(channel -> {
|
||||
String channelId = channel.getUID().getId();
|
||||
if (isLinked(channelId)) {
|
||||
updateState(channelId, getChannelState(channelId, theSynop));
|
||||
updateState(channelId, getChannelState(channelId, synop));
|
||||
}
|
||||
});
|
||||
});
|
||||
}, () -> updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "No Synop message available"));
|
||||
}
|
||||
|
||||
private State getChannelState(String channelId, Synop synop) {
|
||||
int octa = synop.getOcta();
|
||||
switch (channelId) {
|
||||
case HORIZONTAL_VISIBILITY:
|
||||
return new StringType(synop.getHorizontalVisibility().name());
|
||||
case OCTA:
|
||||
return new DecimalType(Math.max(0, synop.getOcta()));
|
||||
return octa >= 0 ? new DecimalType(octa) : UnDefType.NULL;
|
||||
case ATTENUATION_FACTOR:
|
||||
double kc = Math.max(0, Math.min(synop.getOcta(), OCTA_MAX)) / OCTA_MAX;
|
||||
kc = 1 - 0.75 * Math.pow(kc, KASTEN_POWER);
|
||||
return new DecimalType(kc);
|
||||
if (octa >= 0) {
|
||||
double kc = Math.max(0, Math.min(octa, OCTA_MAX)) / OCTA_MAX;
|
||||
kc = 1 - 0.75 * Math.pow(kc, KASTEN_POWER);
|
||||
return new DecimalType(kc);
|
||||
}
|
||||
return UnDefType.NULL;
|
||||
case OVERCAST:
|
||||
int octa = synop.getOcta();
|
||||
Overcast overcast = Overcast.fromOcta(octa);
|
||||
return overcast == Overcast.UNDEFINED ? UnDefType.NULL : new StringType(overcast.name());
|
||||
case PRESSURE:
|
||||
|
@ -190,15 +190,14 @@ public class SynopAnalyzerHandler extends BaseThingHandler {
|
|||
return getWindStrength(synop);
|
||||
case WIND_SPEED_BEAUFORT:
|
||||
QuantityType<Speed> wsKpH = getWindStrength(synop).toUnit(SIUnits.KILOMETRE_PER_HOUR);
|
||||
return (wsKpH != null) ? new DecimalType(Math.round(Math.pow(wsKpH.floatValue() / 3.01, 0.666666666)))
|
||||
return wsKpH != null ? new DecimalType(Math.round(Math.pow(wsKpH.floatValue() / 3.01, 0.666666666)))
|
||||
: UnDefType.NULL;
|
||||
case TIME_UTC:
|
||||
ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
|
||||
int year = synop.getYear() == 0 ? now.getYear() : synop.getYear();
|
||||
int month = synop.getMonth() == 0 ? now.getMonth().getValue() : synop.getMonth();
|
||||
ZonedDateTime zdt = ZonedDateTime.of(year, month, synop.getDay(), synop.getHour(), 0, 0, 0,
|
||||
ZoneOffset.UTC);
|
||||
return new DateTimeType(zdt);
|
||||
return new DateTimeType(
|
||||
ZonedDateTime.of(year, month, synop.getDay(), synop.getHour(), 0, 0, 0, ZoneOffset.UTC));
|
||||
default:
|
||||
logger.error("Unsupported channel Id '{}'", channelId);
|
||||
return UnDefType.UNDEF;
|
||||
|
@ -232,17 +231,14 @@ public class SynopAnalyzerHandler extends BaseThingHandler {
|
|||
|
||||
@Override
|
||||
public void dispose() {
|
||||
ScheduledFuture<?> job = this.executionJob;
|
||||
if (job != null && !job.isCancelled()) {
|
||||
job.cancel(true);
|
||||
}
|
||||
executionJob = null;
|
||||
refreshJob.ifPresent(job -> job.cancel(true));
|
||||
refreshJob = Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
if (command == RefreshType.REFRESH) {
|
||||
updateSynopChannels();
|
||||
updateChannels();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
* Copyright (c) 2010-2022 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.synopanalyzer.internal.stationdb;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link Station} is a DTO for stations.json database.
|
||||
*
|
||||
* @author Gaël L'hopital - Initial Contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Station {
|
||||
public int idOmm;
|
||||
public String usualName = "";
|
||||
private double latitude;
|
||||
private double longitude;
|
||||
|
||||
public String getLocation() {
|
||||
return Double.toString(latitude) + "," + Double.toString(longitude);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/**
|
||||
* Copyright (c) 2010-2022 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.synopanalyzer.internal.stationdb;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.FieldNamingPolicy;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonIOException;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
/**
|
||||
* The {@link StationDbService} makes available a list of known Synop stations.
|
||||
*
|
||||
* @author Gaël L'hopital - Initial Contribution
|
||||
*/
|
||||
|
||||
@Component(service = StationDbService.class)
|
||||
@NonNullByDefault
|
||||
public class StationDbService {
|
||||
private final Logger logger = LoggerFactory.getLogger(StationDbService.class);
|
||||
|
||||
private List<Station> stations;
|
||||
|
||||
@Activate
|
||||
public StationDbService() {
|
||||
try (InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("/db/stations.json");
|
||||
Reader reader = new InputStreamReader(is, StandardCharsets.UTF_8);) {
|
||||
Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
|
||||
stations = Arrays.asList(gson.fromJson(reader, Station[].class));
|
||||
} catch (IOException | JsonSyntaxException | JsonIOException e) {
|
||||
logger.warn("Unable to load station list : {}", e.getMessage());
|
||||
stations = List.of();
|
||||
}
|
||||
}
|
||||
|
||||
public List<Station> getStations() {
|
||||
return stations;
|
||||
}
|
||||
}
|
|
@ -12,11 +12,14 @@
|
|||
*/
|
||||
package org.openhab.binding.synopanalyzer.internal.synop;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link WindDirections} enum possible overcast descriptions
|
||||
*
|
||||
* @author Gaël L'hopital - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum Overcast {
|
||||
UNDEFINED,
|
||||
CLEAR_SKY,
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2010-2022 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.synopanalyzer.internal.synop;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link StationDB} creates is a DTO for stations.json database.
|
||||
*
|
||||
* @author Gaël L'hopital - Initial Contribution
|
||||
*/
|
||||
public class StationDB {
|
||||
public class Station {
|
||||
public String country;
|
||||
public String pack;
|
||||
@SerializedName("id_omm")
|
||||
public int idOmm;
|
||||
@SerializedName("numer_sta")
|
||||
public long numerSta;
|
||||
@SerializedName("usual_name")
|
||||
public String usualName;
|
||||
public double latitude;
|
||||
public double longitude;
|
||||
public double elevation;
|
||||
@SerializedName("station_type")
|
||||
public int stationType;
|
||||
|
||||
public String getLocation() {
|
||||
return Double.toString(latitude) + "," + Double.toString(longitude);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Station> stations;
|
||||
}
|
|
@ -30,14 +30,14 @@ import org.openhab.core.library.unit.Units;
|
|||
@NonNullByDefault
|
||||
public abstract class Synop {
|
||||
protected static final int INITIAL_VALUE = -1000;
|
||||
protected static final char PLUS_SIGN_TEMPERATURE = '0';
|
||||
protected static final char MINUS_SIGN_TEMPERATURE = '1';
|
||||
private static final char PLUS_SIGN_TEMPERATURE = '0';
|
||||
private static final char MINUS_SIGN_TEMPERATURE = '1';
|
||||
|
||||
/*
|
||||
* WS - WIND SPEED
|
||||
*/
|
||||
protected static final int WS_WILDTYPE_IN_MPS = 0;
|
||||
protected static final int WS_ANEMOMETER_IN_MPS = 1;
|
||||
private static final int WS_WILDTYPE_IN_MPS = 0;
|
||||
private static final int WS_ANEMOMETER_IN_MPS = 1;
|
||||
|
||||
/*
|
||||
* HV - HORIZONTAL VISIBILITY [IN KILOMETERS]
|
||||
|
@ -59,12 +59,12 @@ public abstract class Synop {
|
|||
* 99 - > 50 km
|
||||
* HP - high precision
|
||||
*/
|
||||
protected static final int HV_LESS_THAN_1_LIMIT = 10;
|
||||
protected static final int HV_LESS_THAN_10_LIMIT = 60;
|
||||
protected static final int HV_LESS_THAN_50_LIMIT = 84;
|
||||
protected static final int HV_LESS_THAN_1_HP_LIMIT = 93;
|
||||
protected static final int HV_LESS_THAN_10_HP_LIMIT = 96;
|
||||
protected static final int HV_LESS_THAN_50_HP_LIMIT = 98;
|
||||
private static final int HV_LESS_THAN_1_LIMIT = 10;
|
||||
private static final int HV_LESS_THAN_10_LIMIT = 60;
|
||||
private static final int HV_LESS_THAN_50_LIMIT = 84;
|
||||
private static final int HV_LESS_THAN_1_HP_LIMIT = 93;
|
||||
private static final int HV_LESS_THAN_10_HP_LIMIT = 96;
|
||||
private static final int HV_LESS_THAN_50_HP_LIMIT = 98;
|
||||
|
||||
public static enum HorizontalVisibility {
|
||||
UNDEFINED,
|
||||
|
@ -74,7 +74,7 @@ public abstract class Synop {
|
|||
MORE_THAN_50
|
||||
}
|
||||
|
||||
private final int VALID_STRING_LENGTH = 5;
|
||||
private static final int VALID_STRING_LENGTH = 5;
|
||||
|
||||
protected final List<String> stringArray;
|
||||
|
||||
|
@ -107,6 +107,14 @@ public abstract class Synop {
|
|||
setPressure();
|
||||
}
|
||||
|
||||
protected abstract void setTemperatureString();
|
||||
|
||||
protected abstract void setHorizontalVisibilityInt();
|
||||
|
||||
protected abstract void setPressureString();
|
||||
|
||||
protected abstract void setWindString();
|
||||
|
||||
private void setDateHourAndWindIndicator() {
|
||||
String dayHourAndWindIndicator = "";
|
||||
|
||||
|
@ -147,9 +155,7 @@ public abstract class Synop {
|
|||
|
||||
private void setHorizontalVisibility() {
|
||||
setHorizontalVisibilityInt();
|
||||
|
||||
if (horizontalVisibilityInt != INITIAL_VALUE) {
|
||||
|
||||
if (horizontalVisibilityInt < HV_LESS_THAN_1_LIMIT || horizontalVisibilityInt < HV_LESS_THAN_1_HP_LIMIT) {
|
||||
horizontalVisibility = HorizontalVisibility.LESS_THAN_1;
|
||||
} else if (horizontalVisibilityInt < HV_LESS_THAN_10_LIMIT
|
||||
|
@ -166,8 +172,6 @@ public abstract class Synop {
|
|||
}
|
||||
}
|
||||
|
||||
protected abstract void setHorizontalVisibilityInt();
|
||||
|
||||
private void setTemperature() {
|
||||
setTemperatureString();
|
||||
temperature = INITIAL_VALUE;
|
||||
|
@ -183,12 +187,11 @@ public abstract class Synop {
|
|||
}
|
||||
}
|
||||
|
||||
protected abstract void setTemperatureString();
|
||||
|
||||
private void setWindAndOvercast() {
|
||||
setWindString();
|
||||
if (windString != null) {
|
||||
String gustyFlag = windString.substring(0, 2);
|
||||
String localWind = windString;
|
||||
if (localWind != null) {
|
||||
String gustyFlag = localWind.substring(0, 2);
|
||||
if ("00".equals(gustyFlag)) {
|
||||
setWindSpeed(true);
|
||||
} else {
|
||||
|
@ -203,18 +206,20 @@ public abstract class Synop {
|
|||
}
|
||||
|
||||
private void setOcta() {
|
||||
if (windString != null) {
|
||||
octa = Character.getNumericValue(windString.charAt(0));
|
||||
String localWind = windString;
|
||||
if (localWind != null) {
|
||||
octa = Character.getNumericValue(localWind.charAt(0));
|
||||
} else {
|
||||
octa = -1;
|
||||
}
|
||||
}
|
||||
|
||||
private void setWindDirection() {
|
||||
if (windString != null) {
|
||||
String windDirectionString = windString.substring(1, 3);
|
||||
String localWind = windString;
|
||||
if (localWind != null) {
|
||||
String windDirectionString = localWind.substring(1, 3);
|
||||
|
||||
if (windDirectionString.equals("99") || windDirectionString.equals("||")) {
|
||||
if ("99".equals(windDirectionString) || "||".equals(windDirectionString)) {
|
||||
windDirection = INITIAL_VALUE;
|
||||
} else {
|
||||
try {
|
||||
|
@ -228,8 +233,9 @@ public abstract class Synop {
|
|||
|
||||
private void setWindSpeed(boolean gustyWind) {
|
||||
String speedString = null;
|
||||
if (windString != null) {
|
||||
speedString = windString.substring(gustyWind ? 2 : 3, 5);
|
||||
String localWind = windString;
|
||||
if (localWind != null) {
|
||||
speedString = localWind.substring(gustyWind ? 2 : 3, 5);
|
||||
try {
|
||||
windSpeed = Integer.parseInt(speedString);
|
||||
} catch (NumberFormatException e) {
|
||||
|
@ -238,19 +244,14 @@ public abstract class Synop {
|
|||
}
|
||||
}
|
||||
|
||||
protected abstract void setWindString();
|
||||
|
||||
private void setPressure() {
|
||||
setPressureString();
|
||||
|
||||
if (pressureString != null) {
|
||||
|
||||
String pressureTemp = pressureString.substring(1, 5);
|
||||
|
||||
String localPressure = pressureString;
|
||||
if (localPressure != null) {
|
||||
String pressureTemp = localPressure.substring(1, 5);
|
||||
if (pressureTemp.charAt(0) == '0') {
|
||||
pressureTemp = '1' + pressureTemp;
|
||||
}
|
||||
|
||||
try {
|
||||
pressure = (float) Integer.parseInt(pressureTemp) / 10;
|
||||
} catch (NumberFormatException e) {
|
||||
|
@ -259,8 +260,6 @@ public abstract class Synop {
|
|||
}
|
||||
}
|
||||
|
||||
protected abstract void setPressureString();
|
||||
|
||||
protected boolean isValidString(String str) {
|
||||
return (str.length() == VALID_STRING_LENGTH);
|
||||
}
|
||||
|
|
|
@ -12,11 +12,14 @@
|
|||
*/
|
||||
package org.openhab.binding.synopanalyzer.internal.synop;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link WindDirections} enum possible wind directions
|
||||
*
|
||||
* @author Gaël L'hopital - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum WindDirections {
|
||||
N,
|
||||
NNE,
|
||||
|
@ -39,8 +42,8 @@ public enum WindDirections {
|
|||
* Returns the wind direction based on degree.
|
||||
*/
|
||||
public static WindDirections getWindDirection(int degree) {
|
||||
double step = 360.0 / WindDirections.values().length;
|
||||
double step = 360.0 / values().length;
|
||||
double b = Math.floor((degree + (step / 2.0)) / step);
|
||||
return WindDirections.values()[(int) (b % WindDirections.values().length)];
|
||||
return values()[(int) (b % values().length)];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
{
|
||||
"stations":[
|
||||
[
|
||||
{
|
||||
"country":"FR",
|
||||
"pack":"RADOME",
|
||||
|
@ -2420,5 +2419,4 @@
|
|||
"elevation":1133,
|
||||
"station_type":1
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
Loading…
Reference in New Issue