src/main/java/dev/viper/weathertime/WeatherFetcher.java aktualisiert
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user