src/main/java/dev/viper/weathertime/WeatherFetcher.java aktualisiert
This commit is contained in:
@@ -1,123 +1,158 @@
|
|||||||
package dev.viper.weathertime;
|
package dev.viper.weathertime;
|
||||||
|
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import org.json.JSONArray;
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
public class WeatherFetcher {
|
/**
|
||||||
|
* Holt Wetter und Zeitdaten asynchron von OpenWeatherMap.
|
||||||
private final String apiKey;
|
* Liefert WeatherTimeData zurück, mit konsistentem Modell und Fehlerhandling.
|
||||||
private final String location;
|
* Erweiterung: Erfasst Luftfeuchtigkeit, Windgeschwindigkeit, Sonnenauf- und -untergang.
|
||||||
private final String units;
|
*/
|
||||||
private final Logger logger;
|
public class WeatherFetcher {
|
||||||
|
|
||||||
public WeatherFetcher(String apiKey, String location, String units, Logger logger) {
|
private final String apiKey;
|
||||||
this.apiKey = apiKey;
|
private final String location;
|
||||||
this.location = location;
|
private final String units;
|
||||||
this.units = units.toLowerCase();
|
private final Logger logger;
|
||||||
this.logger = logger;
|
|
||||||
if (!this.units.equals("metric") && !this.units.equals("imperial")) {
|
public WeatherFetcher(String apiKey, String location, String units, Logger logger) {
|
||||||
logger.warning("Ungültige Einheit für " + location + ": " + units + ". Verwende 'metric' als Fallback.");
|
this.apiKey = apiKey == null ? "" : apiKey.trim();
|
||||||
}
|
this.location = location == null ? "Berlin,de" : location.trim();
|
||||||
}
|
this.units = units == null ? "metric" : units.trim().toLowerCase();
|
||||||
|
this.logger = logger;
|
||||||
public WeatherData fetch() throws Exception {
|
if (!this.units.equals("metric") && !this.units.equals("imperial")) {
|
||||||
String effectiveUnits = units.equals("metric") || units.equals("imperial") ? units : "metric";
|
logger.warning("Ungültige Einheit für " + this.location + ": " + this.units + ". Verwende 'metric' als Fallback.");
|
||||||
|
}
|
||||||
String urlString = String.format(
|
}
|
||||||
"https://api.openweathermap.org/data/2.5/weather?q=%s&appid=%s&units=%s",
|
|
||||||
location, apiKey, effectiveUnits);
|
/**
|
||||||
|
* Holt die aktuellen Wetter- und Zeitdaten inklusive Zusatzinfos.
|
||||||
URL url = new URL(urlString);
|
* Wirft RuntimeExceptions mit klaren Messages bei Fehlern.
|
||||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
*/
|
||||||
connection.setRequestMethod("GET");
|
public WeatherTimeData fetchAsWeatherTimeData() throws Exception {
|
||||||
connection.setConnectTimeout(5000);
|
if (apiKey.isEmpty()) throw new RuntimeException("API-Key fehlt.");
|
||||||
connection.setReadTimeout(5000);
|
String effectiveUnits = (units.equals("metric") || units.equals("imperial")) ? units : "metric";
|
||||||
|
String urlString = String.format(
|
||||||
int status = connection.getResponseCode();
|
"https://api.openweathermap.org/data/2.5/weather?q=%s&appid=%s&units=%s",
|
||||||
if (status != 200) {
|
location, apiKey, effectiveUnits);
|
||||||
logger.warning("HTTP-Fehlercode: " + status + " für Ort: " + location);
|
|
||||||
throw new RuntimeException("HTTP-Fehlercode: " + status + " für Ort: " + location);
|
try {
|
||||||
}
|
JSONObject json;
|
||||||
|
try (BufferedReader in = new BufferedReader(new InputStreamReader(openConnectionStream(urlString)))) {
|
||||||
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
StringBuilder content = new StringBuilder();
|
||||||
StringBuilder content = new StringBuilder();
|
String inputLine;
|
||||||
String inputLine;
|
while ((inputLine = in.readLine()) != null) {
|
||||||
|
content.append(inputLine);
|
||||||
while ((inputLine = in.readLine()) != null) {
|
}
|
||||||
content.append(inputLine);
|
json = new JSONObject(content.toString());
|
||||||
}
|
}
|
||||||
in.close();
|
|
||||||
connection.disconnect();
|
// Fehlerfall: Antwort-Code ungleich 200
|
||||||
|
if (json.has("cod") && json.getInt("cod") != 200) {
|
||||||
JSONObject json = new JSONObject(content.toString());
|
String msg = json.has("message") ? json.getString("message") : "Unbekannter Fehler";
|
||||||
long dt = json.getLong("dt");
|
logger.warning("API Error für " + location + ": " + msg);
|
||||||
int timezoneShift;
|
throw new RuntimeException(msg);
|
||||||
try {
|
}
|
||||||
timezoneShift = json.getInt("timezone");
|
|
||||||
} catch (Exception e) {
|
long dt = json.getLong("dt");
|
||||||
logger.warning("Fehler beim Abrufen der Zeitzone für Ort: " + location + ": " + e.getMessage());
|
int timezoneShift = json.optInt("timezone", 0); // Zeitzonen-Offset in Sekunden
|
||||||
throw new RuntimeException("Fehler beim Abrufen der Zeitzone für Ort: " + location, e);
|
|
||||||
}
|
ZonedDateTime dateTime = Instant.ofEpochSecond(dt)
|
||||||
ZonedDateTime dateTime = Instant.ofEpochSecond(dt).atZone(ZoneId.of("UTC")).plusSeconds(timezoneShift);
|
.atZone(ZoneId.of("UTC"))
|
||||||
String weatherMain = json.getJSONArray("weather").getJSONObject(0).getString("main");
|
.plusSeconds(timezoneShift);
|
||||||
double temperature = json.getJSONObject("main").getDouble("temp");
|
|
||||||
|
String weatherMain = json.getJSONArray("weather").getJSONObject(0).getString("main");
|
||||||
if (effectiveUnits.equals("imperial") && (temperature < -50 || temperature > 150)) {
|
double temperature = json.getJSONObject("main").getDouble("temp");
|
||||||
logger.warning("Unrealistische Temperatur für " + location + ": " + temperature + "°F. API-Fehler?");
|
|
||||||
} else if (effectiveUnits.equals("metric") && (temperature < -50 || temperature > 60)) {
|
if (effectiveUnits.equals("imperial") && (temperature < -50 || temperature > 150)) {
|
||||||
logger.warning("Unrealistische Temperatur für " + location + ": " + temperature + "°C. API-Fehler?");
|
logger.warning("Unrealistische Temperatur für " + location + ": " + temperature + "°F. API-Fehler?");
|
||||||
}
|
} else if (effectiveUnits.equals("metric") && (temperature < -50 || temperature > 60)) {
|
||||||
|
logger.warning("Unrealistische Temperatur für " + location + ": " + temperature + "°C. API-Fehler?");
|
||||||
return new WeatherData(dateTime, weatherMain, temperature);
|
}
|
||||||
}
|
|
||||||
|
// Temperatur immer in Celsius für WeatherTimeData speichern
|
||||||
public JSONObject fetchForecast() throws Exception {
|
double tempCelsius = effectiveUnits.equals("imperial") ? (temperature - 32) * 5 / 9 : temperature;
|
||||||
String effectiveUnits = units.equals("metric") || units.equals("imperial") ? units : "metric";
|
|
||||||
|
// NEUE FELDER AUSLESEN
|
||||||
String urlString = String.format(
|
int humidity = json.getJSONObject("main").getInt("humidity");
|
||||||
"https://api.openweathermap.org/data/2.5/forecast?q=%s&appid=%s&units=%s",
|
double windSpeed = json.getJSONObject("wind").optDouble("speed", 0.0);
|
||||||
location, apiKey, effectiveUnits);
|
|
||||||
URL url = new URL(urlString);
|
ZonedDateTime sunrise = Instant.ofEpochSecond(json.getJSONObject("sys").getLong("sunrise"))
|
||||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
.atZone(ZoneId.of("UTC"))
|
||||||
connection.setRequestMethod("GET");
|
.plusSeconds(timezoneShift);
|
||||||
connection.setConnectTimeout(5000);
|
|
||||||
connection.setReadTimeout(5000);
|
ZonedDateTime sunset = Instant.ofEpochSecond(json.getJSONObject("sys").getLong("sunset"))
|
||||||
|
.atZone(ZoneId.of("UTC"))
|
||||||
int status = connection.getResponseCode();
|
.plusSeconds(timezoneShift);
|
||||||
if (status != 200) {
|
|
||||||
logger.warning("HTTP-Fehlercode: " + status + " für Ort: " + location);
|
return new WeatherTimeData(dateTime, weatherMain, tempCelsius,
|
||||||
throw new RuntimeException("HTTP-Fehlercode: " + status + " für Ort: " + location);
|
humidity, windSpeed, sunrise, sunset);
|
||||||
}
|
|
||||||
|
} catch (RuntimeException ru) {
|
||||||
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
throw ru;
|
||||||
StringBuilder content = new StringBuilder();
|
} catch (Exception ex) {
|
||||||
String inputLine;
|
logger.warning("Fehler beim Abrufen von OpenWeatherMap: " + ex.getMessage());
|
||||||
while ((inputLine = in.readLine()) != null) {
|
throw new RuntimeException("Verbindung oder API-Fehler: " + ex.getMessage(), ex);
|
||||||
content.append(inputLine);
|
}
|
||||||
}
|
}
|
||||||
in.close();
|
|
||||||
connection.disconnect();
|
/**
|
||||||
|
* Holt das Wetter-Vorhersage-JSON (5 Tage, 3-Stunden-Takt).
|
||||||
return new JSONObject(content.toString());
|
* Muss im Command asynchron ausgewertet werden!
|
||||||
}
|
*/
|
||||||
|
public JSONObject fetchForecast() throws Exception {
|
||||||
public static class WeatherData {
|
if (apiKey.isEmpty()) throw new RuntimeException("API-Key fehlt.");
|
||||||
ZonedDateTime dateTime;
|
String effectiveUnits = (units.equals("metric") || units.equals("imperial")) ? units : "metric";
|
||||||
String weatherMain;
|
String urlString = String.format(
|
||||||
double temperature;
|
"https://api.openweathermap.org/data/2.5/forecast?q=%s&appid=%s&units=%s",
|
||||||
|
location, apiKey, effectiveUnits);
|
||||||
public WeatherData(ZonedDateTime dateTime, String weatherMain, double temperature) {
|
|
||||||
this.dateTime = dateTime;
|
try (BufferedReader in = new BufferedReader(new InputStreamReader(openConnectionStream(urlString)))) {
|
||||||
this.weatherMain = weatherMain;
|
StringBuilder content = new StringBuilder();
|
||||||
this.temperature = temperature;
|
String inputLine;
|
||||||
}
|
while ((inputLine = in.readLine()) != null) {
|
||||||
}
|
content.append(inputLine);
|
||||||
}
|
}
|
||||||
|
JSONObject json = new JSONObject(content.toString());
|
||||||
|
if (json.has("cod") && (!"200".equals(json.get("cod").toString()))) {
|
||||||
|
String msg = json.has("message") ? json.getString("message") : "Unbekannter Fehler";
|
||||||
|
logger.warning("API Error (Forecast) für " + location + ": " + msg);
|
||||||
|
throw new RuntimeException(msg);
|
||||||
|
}
|
||||||
|
return json;
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.warning("Fehler beim Abrufen der Wettervorhersage: " + e.getMessage());
|
||||||
|
throw new RuntimeException("Fehler beim Abrufen der Wettervorhersage: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Öffnet eine HTTP-GET-Verbindung und liefert den InputStream der Response zurück (Timeouts gesetzt). */
|
||||||
|
private java.io.InputStream openConnectionStream(String urlString) throws Exception {
|
||||||
|
URL url = new URL(urlString);
|
||||||
|
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||||
|
connection.setRequestMethod("GET");
|
||||||
|
connection.setConnectTimeout(6000);
|
||||||
|
connection.setReadTimeout(6000);
|
||||||
|
|
||||||
|
int status = connection.getResponseCode();
|
||||||
|
if (status != 200) {
|
||||||
|
String err = "(keine Fehlerdetails)";
|
||||||
|
try (BufferedReader errIn = new BufferedReader(new InputStreamReader(connection.getErrorStream()))) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
String l;
|
||||||
|
while ((l = errIn.readLine()) != null) sb.append(l);
|
||||||
|
err = sb.toString();
|
||||||
|
} catch (Exception suppress) {}
|
||||||
|
throw new RuntimeException("HTTP-Fehlercode: " + status + " – " + err);
|
||||||
|
}
|
||||||
|
return connection.getInputStream();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user