package eirb.pg203; import eirb.pg203.exceptions.WeatherFetchingException; import eirb.pg203.exceptions.WeatherFetchingExceptionApi; import org.json.JSONObject; import eirb.pg203.utils.JSONFetcher; import java.io.IOException; import java.net.URI; import java.net.URL; import java.time.Clock; import java.time.Instant; import java.util.ArrayList; import java.util.Locale; import eirb.pg203.WeatherData.Condition; // https://api.open-meteo.com/v1/forecast?latitude=52.52&longitude=13.41&hourly=temperature_2m /** * OpenMeteo implementation */ public class OpenMeteo implements WeatherDataAPI { private static final String forecastBaseURL = "https://api.open-meteo.com/v1/forecast"; private static final String dailyQuery = "weather_code,temperature_2m_max,temperature_2m_min,wind_speed_10m_max,wind_direction_10m_dominant"; JSONFetcher JSONFetcher = new JSONFetcher(); Clock clock = Clock.systemUTC(); /** * Default constructor */ public OpenMeteo() {} // https://www.nodc.noaa.gov/archive/arc0021/0002199/1.1/data/0-data/HTML/WMO-CODE/WMO4677.HTM private JSONObject fetchWeather(int days, City city) throws WeatherFetchingException{ URL url = null; try { url = URI.create( String.format(Locale.ENGLISH, forecastBaseURL + "?latitude=%.2f&longitude=%.2f&forecast_days=%d&daily=" + dailyQuery, city.getCityCoords().getLat(), city.getCityCoords().getLon(), days ) ).toURL(); } catch (IOException e) { throw new WeatherFetchingException("Impossible to get city coords"); } try { return JSONFetcher.fetch(url); } catch (IOException e) { throw new WeatherFetchingExceptionApi(); } } /** * return condition based on the WMOCode * table can be found here : https://open-meteo.com/en/docs (at the end) * @param WMOCode id code * @return weather condition */ private static Condition getConditionFromCode(int WMOCode) { return switch (WMOCode) { case 0, 1 -> Condition.SUNNY; case 2 -> Condition.PARTIAL; case 3 -> Condition.CLOUDY; case 61, 63, 65, 80, 81, 82 -> Condition.RAINY; default -> Condition.ERROR; }; } private WeatherData getWeatherDataFromForecast(JSONObject response, int day, String city) { JSONObject daily = response.getJSONObject("daily"); float max_temp = daily.getJSONArray("temperature_2m_max").getFloat(day); float min_temp = daily.getJSONArray("temperature_2m_min").getFloat(day); float temp_c = (min_temp + max_temp) / 2; float windSpeed = daily.getJSONArray("wind_speed_10m_max").getFloat(day); float windDirection = daily.getJSONArray("wind_direction_10m_dominant").getFloat(day); int conditionCode = daily.getJSONArray("weather_code").getInt(day); return new WeatherData( new City(city), Instant.now(clock), temp_c, windSpeed, windDirection, getConditionFromCode(conditionCode) ); } /** * @param day Day, 0 ≤ day ≤ 14 */ @Override public WeatherData getTemperature(int day, String city) throws WeatherFetchingException { JSONObject result = fetchWeather(day + 1, new City(city)); return getWeatherDataFromForecast(result, day, city); } @Override public WeatherData getTemperature(int day, int hour, String city) throws WeatherFetchingException{ return getTemperature(day, city); } @Override public ArrayList getTemperatures(int days, String city) throws WeatherFetchingException{ JSONObject result = fetchWeather(days, new City(city)); ArrayList weatherDatas = new ArrayList<>(); for (int day = 0; day < days; ++day) { weatherDatas.add( getWeatherDataFromForecast(result, day, city) ); } return weatherDatas; } @Override public String getAPIName() { return "OpenMeteo"; } @Override public String toString() { return this.getAPIName(); } }