src/main/java/dev/viper/weathertime/WeatherFetcher.java aktualisiert

This commit is contained in:
2025-08-09 20:58:43 +00:00
parent ac318f4f78
commit 7ae5eea24a

View File

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