feat: use WeatherData instead of Temperature

This commit is contained in:
Nemo D'ACREMONT 2024-11-16 16:01:45 +01:00
parent 5fe57da57e
commit 34928424ca
No known key found for this signature in database
GPG Key ID: 6E5BCE8022FA8276
7 changed files with 282 additions and 61 deletions

View File

@ -15,6 +15,7 @@ public class Main {
display.addAPI(openMeteo);
display.addAPI(openWeatherMap);
display.display(5, "Bordeaux");
// weatherAPI can't fetch for more than 3 days with free plan
display.display(3, "Bordeaux");
}
}

View File

@ -9,15 +9,18 @@ import java.net.URI;
import java.net.URL;
import java.time.Instant;
import java.util.ArrayList;
import eirb.pg203.WeatherData.Condition;
// https://api.open-meteo.com/v1/forecast?latitude=52.52&longitude=13.41&hourly=temperature_2m
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";
// 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 IOException {
URL url = URI.create(
String.format(forecastBaseURL + "?latitude=%.2f&longitude=%.2f&forecast_days=%d&daily=apparent_temperature_min,apparent_temperature_max",
String.format(forecastBaseURL + "?latitude=%.2f&longitude=%.2f&forecast_days=%d&daily=" + dailyQuery,
city.getCityCoords().getLat(),
city.getCityCoords().getLon(),
days
@ -27,34 +30,66 @@ public class OpenMeteo implements WeatherDataAPI {
return JSONFetcher.fetch(url);
}
private static Condition getConditionFromCode(int WMOCode) {
if (WMOCode < 20)
return Condition.SUNNY;
else if (WMOCode < 30)
return Condition.RAINY;
else if (WMOCode < 50)
return Condition.CLOUDY;
else
return Condition.RAINY;
}
private static 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(),
temp_c,
windSpeed,
windDirection,
getConditionFromCode(conditionCode)
);
}
/**
* @param day Day, 0 &leq; day &leq; 14
*/
@Override
public Temperature getTemperature(int day, String city) throws IOException {
JSONObject result = fetchWeather(day+1, new City(city));
JSONObject daily = result.getJSONObject("daily");
float temp_c = (daily.getJSONArray("apparent_temperature_max").getFloat(0) + daily.getJSONArray("apparent_temperature_min").getFloat(0)) / 2;
public WeatherData getTemperature(int day, String city) throws IOException {
JSONObject result = fetchWeather(day + 1, new City(city));
return new Temperature(temp_c, new City(city), Instant.now());
return getWeatherDataFromForecast(result, day, city);
}
@Override
public Temperature getTemperature(int day, int hour, String city) throws IOException{
public WeatherData getTemperature(int day, int hour, String city) throws IOException{
return getTemperature(day, city);
}
@Override
public ArrayList<Temperature> getTemperatures(int days, String city) throws IOException {
JSONObject result = fetchWeather(days, new City(city));
ArrayList<Temperature> temperatures = new ArrayList<>();
JSONObject daily = result.getJSONObject("daily");
for (int day = 0; day < days; ++day) {
float temp_c = (daily.getJSONArray("apparent_temperature_max").getFloat(day) + daily.getJSONArray("apparent_temperature_min").getFloat(day)) / 2;
temperatures.add(new Temperature(temp_c, new City(city), Instant.now()));
}
return temperatures;
}
@Override
public ArrayList<WeatherData> getTemperatures(int days, String city) throws IOException {
JSONObject result = fetchWeather(days, new City(city));
ArrayList<WeatherData> weatherDatas = new ArrayList<>();
for (int day = 0; day < days; ++day) {
weatherDatas.add(
getWeatherDataFromForecast(result, day, city)
);
}
return weatherDatas;
}
@Override
public String getAPIName() {

View File

@ -12,6 +12,7 @@ import java.time.DayOfWeek;
import java.time.Instant;
import java.time.ZoneId;
import java.util.ArrayList;
import eirb.pg203.WeatherData.Condition;
// https://api.open-meteo.com/v1/forecast?latitude=52.52&longitude=13.41&hourly=temperature_2m
@ -36,43 +37,91 @@ public class OpenWeatherMap implements WeatherDataAPI {
return JSONFetcher.fetch(url);
}
private static WeatherData getWeatherDataFromForecast(JSONObject response, int day, String city) {
JSONArray list = response.getJSONArray("list");
DayOfWeek targetedDay = Instant.now().plusSeconds(day * 24 * 3600).atZone(ZoneId.systemDefault()).getDayOfWeek();
DayOfWeek dayOfWeek;
int dataCount = 0;
float temp_c = 0;
float windSpeed = 0;
float windDirection = 0;
float pop = 0; // probability of precipitation
float cloudiness = 0; // percent
for (int i = 0 ; i < list.length() ; ++i)
{
JSONObject data = list.getJSONObject(i);
int timestamp = data.getInt("dt");
dayOfWeek = Instant.ofEpochSecond(timestamp).atZone(ZoneId.systemDefault()).getDayOfWeek();
if (dayOfWeek == targetedDay)
{
temp_c += data.getJSONObject("main").getFloat("temp");
windSpeed += data.getJSONObject("wind").getFloat("speed");
windDirection += data.getJSONObject("wind").getFloat("deg");
cloudiness += data.getJSONObject("clouds").getFloat("all");
pop += data.getFloat("pop");
dataCount++;
}
}
if (dataCount != 0)
{
temp_c /= dataCount;
windSpeed /= dataCount;
windDirection /= dataCount;
pop /= dataCount;
cloudiness /= dataCount;
}
Condition condition = Condition.SUNNY;
if (pop > 50)
condition = Condition.RAINY;
else if (cloudiness > 75)
condition = Condition.CLOUDY;
else if (cloudiness > 25)
condition = Condition.PARTIAL;
return new WeatherData(
new City(city),
Instant.now().plusSeconds(day * 24 * 3600),
temp_c,
windSpeed,
windDirection,
condition
);
}
/**
* @param day Day, 0 &leq; day &leq; 14
*/
@Override
public Temperature getTemperature(int day, String city) throws IOException {
public WeatherData getTemperature(int day, String city) throws IOException {
JSONObject result = fetchWeather(day+1, new City(city));
JSONArray list = result.getJSONArray("list");
float temp_c = list.getJSONObject(0).getJSONObject("main").getFloat("temp");
return new Temperature(temp_c, new City(city), Instant.now());
return getWeatherDataFromForecast(result, day, city);
}
@Override
public Temperature getTemperature(int day, int hour, String city) throws IOException{
public WeatherData getTemperature(int day, int hour, String city) throws IOException{
return getTemperature(day, city);
}
@Override
public ArrayList<Temperature> getTemperatures(int days, String city) throws IOException {
public ArrayList<WeatherData> getTemperatures(int days, String city) throws IOException {
JSONObject result = fetchWeather(days, new City(city));
JSONArray list = result.getJSONArray("list");
ArrayList<Temperature> temperatures = new ArrayList<>();
int cnt = result.getInt("cnt");
DayOfWeek day = Instant.now().atZone(ZoneId.systemDefault()).getDayOfWeek();
ArrayList<WeatherData> weatherDatas = new ArrayList<>();
for (int i = 0; i < cnt; ++i) {
JSONObject data = list.getJSONObject(i);
int timestamp = data.getInt("dt");
if (day == Instant.ofEpochSecond(timestamp).atZone(ZoneId.systemDefault()).getDayOfWeek())
{
float temp_c = data.getJSONObject("main").getFloat("temp");
temperatures.add(new Temperature(temp_c, new City(city), Instant.now()));
}
for (int day = 0; day < days ; ++day) {
weatherDatas.add(
getWeatherDataFromForecast(result, day, city)
);
}
return temperatures;
return weatherDatas;
}
@Override

View File

@ -3,6 +3,7 @@ package eirb.pg203;
import org.json.JSONArray;
import org.json.JSONObject;
import eirb.pg203.WeatherData.Condition;
import eirb.pg203.utils.JSONFetcher;
import java.io.IOException;
@ -31,33 +32,73 @@ public class WeatherAPI implements WeatherDataAPI{
return JSONFetcher.fetch(url);
}
private static WeatherData.Condition getConditionFromString(String str) {
if (str.toLowerCase().contains("rain"))
return Condition.RAINY;
else if (str.toLowerCase().contains("partly"))
return Condition.PARTIAL;
else if (str.toLowerCase().contains("cloud"))
return Condition.CLOUDY;
return Condition.SUNNY;
}
private static WeatherData getWeatherDataFromForecast(JSONObject response, int day, String city) {
JSONObject forecastDay = response.getJSONObject("forecast").getJSONArray("forecastday").getJSONObject(day);
JSONArray forecastHour = forecastDay.getJSONArray("hour");
float temp_c = forecastDay.getJSONObject("day").getFloat("avgtemp_c");
// Calculates the mean for the day
float windSpeed = 0;
float windDirection = 0;
for (int i = 0 ; i < forecastHour.length() ; ++i)
{
windSpeed += forecastHour.getJSONObject(i).getFloat("wind_kph");
windDirection += forecastHour.getJSONObject(i).getFloat("wind_degree");
}
windSpeed /= forecastHour.length();
windDirection /= forecastHour.length();
String conditionStr = forecastDay.getJSONObject("day").getJSONObject("condition").getString("text");
return new WeatherData(
new City(city),
Instant.now(),
temp_c,
windSpeed,
windDirection,
getConditionFromString(conditionStr)
);
}
/**
* @param day Day, 0 &leq; day &leq; 14
*/
@Override
public Temperature getTemperature(int day, String city) throws IOException {
public WeatherData getTemperature(int day, String city) throws IOException {
JSONObject result = fetchWeather(day+1, city);
JSONArray forecast = result.getJSONObject("forecast").getJSONArray("forecastday");
float temp_c = forecast.getJSONObject(day).getJSONObject("day").getFloat("avgtemp_c");
return new Temperature(temp_c, new City(city), Instant.now());
return getWeatherDataFromForecast(result, day, city);
}
@Override
public Temperature getTemperature(int day, int hour, String city) throws IOException{
public WeatherData getTemperature(int day, int hour, String city) throws IOException{
return getTemperature(day, city);
}
@Override
public ArrayList<Temperature> getTemperatures(int days, String city) throws IOException {
public ArrayList<WeatherData> getTemperatures(int days, String city) throws IOException {
JSONObject result = fetchWeather(days, city);
ArrayList<Temperature> temperatures = new ArrayList<>();
ArrayList<WeatherData> weatherDatas = new ArrayList<>();
for (int day = 0; day < days; ++day) {
JSONArray forecast = result.getJSONObject("forecast").getJSONArray("forecastday");
float temp_c = forecast.getJSONObject(day).getJSONObject("day").getFloat("avgtemp_c");
temperatures.add(new Temperature(temp_c, new City(city), Instant.now()));
weatherDatas.add(
getWeatherDataFromForecast(result, day, city)
);
}
return temperatures;
return weatherDatas;
}
@Override

View File

@ -0,0 +1,96 @@
package eirb.pg203;
import java.time.Instant;
import java.util.concurrent.locks.Condition;
class WeatherData {
enum Condition {
SUNNY("☀️"),
PARTIAL("🌤"),
CLOUDY("☁️"),
RAINY("🌧"),
ERROR("E");
private String desc;
Condition(String desc) { this.desc = desc; }
@Override
public String toString() {
return this.desc;
}
}
private City city;
private Instant date;
private float temp;
private Condition condition; // cloudly, sunny ...
private float windSpeed;
private float windDirection;
WeatherData(City city, Instant date, float temp, float windSpeed, float windDirection, Condition condition) {
this.city = city;
this.date = date;
this.temp = temp;
this.condition = condition;
this.windSpeed = windSpeed;
this.windDirection = windDirection;
}
public City getCity() {
return city;
}
public Instant getDate() {
return date;
}
public Condition getCondition() {
return condition;
}
public float getTemp() {
return temp;
}
public float getWindSpeed() {
return windSpeed;
}
public float getWindDirection() {
return windDirection;
}
public void setCity(City city) {
this.city = city;
}
public void setDate(Instant date) {
this.date = date;
}
public void setCondition(Condition condition) {
this.condition = condition;
}
public void setTemp(float temp) {
this.temp = temp;
}
public void setWindSpeed(float windSpeed) {
this.windSpeed = windSpeed;
}
public void setWindDirection(float windDirection) {
this.windDirection = windDirection;
}
@Override
public String toString() {
return String.format("%05.2f° %s %05.2fkm/h %06.2f°",
this.getTemp(),
this.getCondition().toString(),
this.getWindSpeed(),
this.getWindDirection()
);
}
}

View File

@ -12,7 +12,7 @@ public interface WeatherDataAPI {
* @return Temperature of the day from the city
* @throws IOException when request failed
*/
Temperature getTemperature(int day, String city) throws IOException;
WeatherData getTemperature(int day, String city) throws IOException;
/**
*
@ -22,9 +22,9 @@ public interface WeatherDataAPI {
* @return Temperature of the day for a hour from the city
* @throws IOException when request failed
*/
Temperature getTemperature(int day, int hour, String city) throws IOException;
WeatherData getTemperature(int day, int hour, String city) throws IOException;
ArrayList<Temperature> getTemperatures(int days, String city) throws IOException;
ArrayList<WeatherData> getTemperatures(int days, String city) throws IOException;
/***
* Name of the API

View File

@ -21,29 +21,28 @@ class WeatherDisplayBasic implements WeatherDisplay {
System.err.println(line);
}
private void displayTemperatures(String ApiName, ArrayList<Temperature> temperatures) {
private void displayWeatherDatas(String ApiName, ArrayList<WeatherData> weatherDatas) {
StringBuilder line = new StringBuilder();
line.append(ApiName);
for (Temperature temp: temperatures) {
for (WeatherData weatherData: weatherDatas) {
line.append('\t')
.append(temp.getTemp());
.append(weatherData.toString());
}
System.err.println(line);
}
public void display(int days, String city) {
ArrayList<Temperature> temperatures;
ArrayList<WeatherData> weatherDatas;
displayHeader(days);
for (WeatherDataAPI w: apis) {
try {
temperatures = w.getTemperatures(days, city);
displayTemperatures(w.getAPIName(), temperatures);
weatherDatas = w.getTemperatures(days, city);
displayWeatherDatas(w.getAPIName(), weatherDatas);
} catch (Exception e) {
System.err.println(e);
System.err.println("ntm++ martin");
}
}
}