*/
@NonNullByDefault
public class SynopAnalyzerDiscoveryService extends AbstractDiscoveryService {
- private final Logger logger = LoggerFactory.getLogger(SynopAnalyzerDiscoveryService.class);
private static final int DISCOVER_TIMEOUT_SECONDS = 5;
- private LocationProvider locationProvider;
- private final StationDB stationDB;
+
+ private final Logger logger = LoggerFactory.getLogger(SynopAnalyzerDiscoveryService.class);
private final Map<Integer, Double> distances = new HashMap<>();
+ private final LocationProvider locationProvider;
+ private final StationDB stationDB;
/**
* Creates a SynopAnalyzerDiscoveryService with enabled autostart.
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, Integer.toString(nearestId)))
- .withLabel("Synop : " + station.get().usualName)
+ 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());
}
public static Overcast fromOcta(int octa) {
if (octa == 0) {
return Overcast.CLEAR_SKY;
- } else if (octa > 0 && octa < 8) {
+ } else if (octa > 0 && octa < 9) {
return Overcast.CLOUDY;
} else if (octa == 9) {
return Overcast.SKY_NOT_VISIBLE;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
-import java.util.Collections;
+import java.nio.charset.StandardCharsets;
import java.util.Hashtable;
-import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
@NonNullByDefault
public class SynopAnalyzerHandlerFactory extends BaseThingHandlerFactory {
private final Logger logger = LoggerFactory.getLogger(SynopAnalyzerHandlerFactory.class);
- private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.singleton(THING_SYNOP);
private final LocationProvider locationProvider;
- private final Gson gson;
- private @NonNullByDefault({}) StationDB stationDB;
+ private final Gson gson = new Gson();
+ private @Nullable StationDB stationDB;
private @Nullable ServiceRegistration<?> serviceReg;
@Activate
public SynopAnalyzerHandlerFactory(@Reference LocationProvider locationProvider) {
this.locationProvider = locationProvider;
- this.gson = new Gson();
}
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
- return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
+ return THING_SYNOP.equals(thingTypeUID);
}
@Override
protected @Nullable ThingHandler createHandler(Thing thing) {
- ThingTypeUID thingTypeUID = thing.getThingTypeUID();
-
- return thingTypeUID.equals(THING_SYNOP) ? new SynopAnalyzerHandler(thing, locationProvider, stationDB) : null;
+ return supportsThingType(thing.getThingTypeUID()) ? new SynopAnalyzerHandler(thing, locationProvider, stationDB)
+ : null;
}
@Override
super.activate(componentContext);
try (InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("/db/stations.json");
- Reader reader = new InputStreamReader(is, "UTF-8");) {
+ Reader reader = new InputStreamReader(is, StandardCharsets.UTF_8);) {
- stationDB = gson.fromJson(reader, StationDB.class);
- registerDiscoveryService();
+ 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");
- stationDB = new StationDB();
}
}
super.deactivate(componentContext);
}
- private void registerDiscoveryService() {
- SynopAnalyzerDiscoveryService discoveryService = new SynopAnalyzerDiscoveryService(stationDB, locationProvider);
+ private void registerDiscoveryService(StationDB stations) {
+ SynopAnalyzerDiscoveryService discoveryService = new SynopAnalyzerDiscoveryService(stations, locationProvider);
serviceReg = bundleContext.registerService(DiscoveryService.class.getName(), discoveryService,
new Hashtable<>());
import java.util.concurrent.TimeUnit;
import javax.measure.quantity.Speed;
+import javax.ws.rs.HttpMethod;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.synopanalyser.internal.synop.Overcast;
import org.openhab.binding.synopanalyser.internal.synop.StationDB;
-import org.openhab.binding.synopanalyser.internal.synop.StationDB.Station;
import org.openhab.binding.synopanalyser.internal.synop.Synop;
import org.openhab.binding.synopanalyser.internal.synop.SynopLand;
import org.openhab.binding.synopanalyser.internal.synop.SynopMobile;
private final Logger logger = LoggerFactory.getLogger(SynopAnalyzerHandler.class);
private @Nullable ScheduledFuture<?> executionJob;
- // private @NonNullByDefault({}) SynopAnalyzerConfiguration configuration;
private @NonNullByDefault({}) String formattedStationId;
private final LocationProvider locationProvider;
- private final StationDB stationDB;
+ private final @Nullable StationDB stationDB;
- public SynopAnalyzerHandler(Thing thing, LocationProvider locationProvider, StationDB stationDB) {
+ public SynopAnalyzerHandler(Thing thing, LocationProvider locationProvider, @Nullable StationDB stationDB) {
super(thing);
this.locationProvider = locationProvider;
this.stationDB = stationDB;
logger.info("Scheduling Synop update thread to run every {} minute for Station '{}'",
configuration.refreshInterval, formattedStationId);
- if (thing.getProperties().isEmpty()) {
- discoverAttributes(configuration.stationId);
+ StationDB stations = stationDB;
+ if (thing.getProperties().isEmpty() && stations != null) {
+ discoverAttributes(stations, configuration.stationId);
}
executionJob = scheduler.scheduleWithFixedDelay(this::updateSynopChannels, 0, configuration.refreshInterval,
TimeUnit.MINUTES);
- updateStatus(ThingStatus.UNKNOWN);
}
- protected void discoverAttributes(int stationId) {
- final Map<String, String> properties = new HashMap<>();
-
- Optional<Station> station = stationDB.stations.stream().filter(s -> stationId == s.idOmm).findFirst();
- station.ifPresent(s -> {
+ 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());
properties.put("Distance", new QuantityType<>(distance, SIUnits.METRE).toString());
}
+ updateProperties(properties);
});
-
- updateProperties(properties);
}
private Optional<Synop> getLastAvailableSynop() {
String url = forgeURL();
try {
- String answer = HttpUtil.executeUrl("GET", url, REQUEST_TIMEOUT_MS);
+ String answer = HttpUtil.executeUrl(HttpMethod.GET, url, REQUEST_TIMEOUT_MS);
List<String> messages = Arrays.asList(answer.split("\n"));
if (!messages.isEmpty()) {
String message = messages.get(messages.size() - 1);
synop.ifPresent(theSynop -> {
getThing().getChannels().forEach(channel -> {
String channelId = channel.getUID().getId();
- updateState(channelId, getChannelState(channelId, theSynop));
+ if (isLinked(channelId)) {
+ updateState(channelId, getChannelState(channelId, theSynop));
+ }
});
});
}
--- /dev/null
+# binding
+binding.synopanalyzer.name = Extension Synop Analyzer
+binding.synopanalyzer.description = Synop Analyzer permet de télécharger et interpréter les messages SYNOP.
+
+# thing type
+thing-type.synopanalyzer.synopanalyzer.label = Message Synop
+thing-type.synopanalyzer.synopanalyzer.description = Décodage du dernier message d'une station Synop.
+
+# channel types
+channel-type.synopanalyzer.wind-speed-beaufort.label = Beaufort
+channel-type.synopanalyzer.wind-speed-beaufort.description = Force du vent sur l'échelle Beaufort.
+
+channel-type.synopanalyzer.wind-direction.label = Direction du vent
+channel-type.synopanalyzer.wind-direction.description = Equivalent cardinal de la direction du vent.
+# Only translating those that needs a french adaptation (containing "W")
+channel-type.synopanalyzer.wind-direction.state.option.SSW = SSO
+channel-type.synopanalyzer.wind-direction.state.option.SW = SO
+channel-type.synopanalyzer.wind-direction.state.option.WSW = OSO
+channel-type.synopanalyzer.wind-direction.state.option.W = O
+channel-type.synopanalyzer.wind-direction.state.option.WNW = ONO
+channel-type.synopanalyzer.wind-direction.state.option.NW = NO
+channel-type.synopanalyzer.wind-direction.state.option.NNW = NNO
+
+channel-type.synopanalyzer.octa.label = Octa
+channel-type.synopanalyzer.octa.description = Evaluation de la couverture nuageuse.
+
+channel-type.synopanalyzer.attenuation-factor.label = Coefficient d'atténuation
+channel-type.synopanalyzer.attenuation-factor.description = Atténuation générée par la couverture nuageuse.
+
+channel-type.synopanalyzer.overcast.label = Couverture nuageuse
+channel-type.synopanalyzer.overcast.description = Appréciation de la couverture nuageuse.
+channel-type.synopanalyzer.overcast.state.option.CLEAR_SKY = Ciel dégagé
+channel-type.synopanalyzer.overcast.state.option.CLOUDY = Nuageux
+channel-type.synopanalyzer.overcast.state.option.SKY_NOT_VISIBLE = Ciel non visible
+
+channel-type.synopanalyzer.horizontal-visibility.label = Visibilité horizontale
+channel-type.synopanalyzer.horizontal-visibility.description = Ordre de grandeur de la visibilité horizontale.
+channel-type.synopanalyzer.horizontal-visibility.state.option.LESS_THAN_1 = Moins de 1 km
+channel-type.synopanalyzer.horizontal-visibility.state.option.LESS_THAN_10 = Entre 1 et 10 km
+channel-type.synopanalyzer.horizontal-visibility.state.option.LESS_THAN_50 = Entre 10 et 50 km
+channel-type.synopanalyzer.horizontal-visibility.state.option.MORE_THAN_50 = Plus de 50 km
+
+channel-type.synopanalyzer.time-utc.label = Horodatage
+channel-type.synopanalyzer.time-utc.description = Heure d'observation des mesures relevées
<thing-type id="synopanalyzer">
<label>Synop Message</label>
- <description>The Synop Analyzer binding decodes Synop messages</description>
+ <description>This is the interpretation of the last message of a given station.</description>
<channels>
<channel id="temperature" typeId="system.outdoor-temperature"/>
<channel id="pressure" typeId="system.barometric-pressure"/>
<channel id="wind-angle" typeId="system.wind-direction"/>
- <channel id="wind-direction" typeId="wind-direction"/>
<channel id="wind-speed" typeId="system.wind-speed"/>
+ <channel id="wind-direction" typeId="wind-direction"/>
<channel id="wind-speed-beaufort" typeId="wind-speed-beaufort"/>
<channel id="overcast" typeId="overcast"/>
<channel id="octa" typeId="octa"/>
<channel-type id="octa">
<item-type>Number</item-type>
<label>Octa</label>
- <description>Octa</description>
+ <description>Cloud cover estimation.</description>
+ <category>sun_clouds</category>
<state readOnly="true" pattern="%d/8" min="0" max="8"/>
</channel-type>
- <channel-type id="attenuation-factor">
+ <channel-type id="attenuation-factor" advanced="true">
<item-type>Number</item-type>
<label>Mitigation Factor</label>
<description>Cloud layer mitigation factor</description>
+ <category>sun_clouds</category>
<state readOnly="true" pattern="%.1f" max="1" min="0"/>
</channel-type>
<item-type>String</item-type>
<label>Overcast</label>
<description>Overcast</description>
+ <category>sun_clouds</category>
<state readOnly="true" pattern="%s">
<options>
<option value="CLEAR_SKY">Clear sky</option>
<item-type>DateTime</item-type>
<label>Observation Time</label>
<description>Timestamp when data was observed</description>
+ <category>time</category>
<state readOnly="true"/>
</channel-type>