Commit 22d0d1b2 authored by Christopher Bohn's avatar Christopher Bohn 🤔
Browse files

Can report minutely data from "onecall" dataset

parent 077a681c
......@@ -70,7 +70,6 @@ code that uses data from [OpenWeathermap.org](https://openweathermap.org).
data set
- [*"onecall"*](https://openweathermap.org/api/one-call-api), the "One
Call API" data set
- Includes *onecall/timemachine*
- [*forecast*](https://openweathermap.org/forecast5), the 5-day/3-hour
forecast data set
- [*air_pollution*](https://openweathermap.org/api/air-pollution), the air
......@@ -86,14 +85,18 @@ code that uses data from [OpenWeathermap.org](https://openweathermap.org).
support the subscription-based APIs.
- As of this writing, `OpenWeatherConnector` only supports the *"weather"*,
*"forecast*, *"air_pollution"*, *"air_pollution/forecast"*, and
*"air_pollution/history"* datasets. We plan to add support for the
*"onecall"* and the *onecall/timemachine* datasets.
*"air_pollution/history"* datasets. We have support for the current and
minutely data in the *"onecall"* dataset and are working on hourly and daily
data.
- We do not currently access the NWS alerts from the *onecall* dataset but will
do so soon.
- We not currently support the *onecall/timemachine* dataset but will do so soon.
- We may add support for the
[Geocoding API](https://openweathermap.org/api/geocoding-api) (*"direct"* and
*"reverse"* data sets).
- We do not anticipate supporting the
[Weather Stations](https://openweathermap.org/stations) API nor the
[Weather Triggers](https://openweathermap.org/triggers) API soon, as they are
[Weather Triggers](https://openweathermap.org/triggers) API, as they are
not needed for our intended use of `OpenWeatherConnector`. (Also,
`RestConnection` does not (yet) support PUSH and PUT calls, which would be
required for those APIs.)
......
......@@ -89,8 +89,7 @@ public class Demonstration {
}
private static void reportAirPollutionHistoryOrForecastData(OpenWeatherConnector weather, Instant now) {
Date timestamp;
timestamp = weather.getTimestamps().get(weather.getTimestamps().size() / 2);
Date timestamp = weather.getTimestamps().get(weather.getTimestamps().size() / 2);
System.out.println("The air quality at " + timestamp +
(timestamp.toInstant().isBefore(now) ? " was " : " will be ") +
weather.getAirQualityIndex(timestamp) + " pollutant concentration");
......@@ -120,6 +119,7 @@ public class Demonstration {
}
private static void reportOneCallData(OpenWeatherConnector weather) {
Date timestamp;
System.out.println("It is currently " + weather.getWeatherCategories());
System.out.println("Specifically, it is " + weather.getWeatherDescriptions());
System.out.println("The temperature is " + weather.getTemperature() + "K");
......@@ -133,14 +133,16 @@ public class Demonstration {
System.out.println("The UV Index is " + weather.getUltravioletIndex());
System.out.println("Precipitation in the last hour has been " + weather.getOneHourRainfall() + "mm of" +
" rain and " + weather.getOneHourSnowfall() + "mm of snow.");
System.out.println("In 30 minutes... (standby)");
System.out.println("In 30 minutes...");
timestamp = weather.getTimestamps().get(weather.getTimestamps("minutely").size() / 2);
System.out.println("\tAt " + timestamp + " the 1-hour (?) precipitation total will be " +
weather.getMinutelyPrecipitation(timestamp));
System.out.println("In 12 hours... (standby)");
System.out.println("In 4 days... (standby)");
}
private static void reportForecastData(OpenWeatherConnector weather) {
Date timestamp;
timestamp = weather.getTimestamps().get(weather.getTimestamps().size() / 2);
Date timestamp = weather.getTimestamps().get(weather.getTimestamps().size() / 2);
System.out.println("At " + timestamp + " it will be " + weather.getWeatherCategories(timestamp));
System.out.println("Specifically, it will be " + weather.getWeatherDescriptions(timestamp));
System.out.println("The temperature will be " + weather.getTemperature(timestamp) + "K");
......
......@@ -393,8 +393,22 @@ public class OpenWeatherConnector {
return currentTimestamp;
}
private List<Date> moveTimestampsFromJsonArrayToJavaList(String jsonListName, List<Date> timestamps) {
if (data.containsKey(jsonListName)) {
JSONArray entries = (JSONArray)data.get(jsonListName);
if (entries != null) {
timestamps = new ArrayList<>(entries.size());
for (Object entry : entries) {
long unixTime = (Long)((JSONObject)entry).get("dt");
timestamps.add(new Date(unixTime * 1000));
}
}
}
return timestamps;
}
/**
* <p>Provides the dates and times for reports with multiple timestamps.</p>
* <p>Provides all dates and times for reports with multiple timestamps.</p>
* <p>Available for all datasets with data in the past or the future.</p>
*
* @throws IllegalStateException if no data has been retrieved using {@link #retrieveData(String)}
......@@ -403,22 +417,28 @@ public class OpenWeatherConnector {
checkForDataReadiness(null);
Set<String> possibleListNames = Set.of("list", "minutely", "hourly", "daily");
List<Date> timestamps = new ArrayList<>();
for (String possibleListName : possibleListNames) {
if (data.containsKey(possibleListName)) {
JSONArray entries = (JSONArray)data.get(possibleListName);
if (entries != null) {
timestamps = new ArrayList<>(entries.size());
for (Object entry : entries) {
long unixTime = (Long)((JSONObject)entry).get("dt");
timestamps.add(new Date(unixTime * 1000));
}
}
}
for (String listName : possibleListNames) {
timestamps = moveTimestampsFromJsonArrayToJavaList(listName, timestamps);
}
timestamps.sort(null);
return List.copyOf(timestamps);
}
/**
* <p>Provides the dates and times for a specific list, for reports with multiple timestamps.</p>
* <p>Available for all datasets with data in the past or the future.</p>
*
* @param listName the name of the list whose timestamps are of interest
* @throws IllegalStateException if no data has been retrieved using {@link #retrieveData(String)}
*/
public List<Date> getTimestamps(String listName) {
checkForDataReadiness(null);
List<Date> timestamps = new ArrayList<>();
timestamps = moveTimestampsFromJsonArrayToJavaList(listName, timestamps);
timestamps.sort(null);
return List.copyOf(timestamps);
}
/*
* Wrapper methods for current and forecasted weather
*/
......@@ -884,6 +904,18 @@ public class OpenWeatherConnector {
return extractDoubleFromJSON(getListEntry("list", timestamp), "snow", "3h", 0.0);
}
/**
* <p>Provides the precipitation column, in millimeters, forecasted for the the specified minute. This appears to be
* a 1-hour total that does not distinguish between rain and snow.</p>
* <p>Available for the "onecall" dataset.</p>
*
* @return the forecasted precipitation total, or 0.0 if precipitation volume is not in the forecast
*/
public double getMinutelyPrecipitation(Date timestamp) {
checkForDataReadiness(Set.of("onecall"));
return extractDoubleFromJSON(getListEntry("minutely", timestamp), "precipitation", 0.0);
}
/*
* Wrapper methods for Air Quality
*/
......
......@@ -6,7 +6,6 @@ import org.junit.Test;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import static org.junit.Assert.fail;
......@@ -37,6 +36,7 @@ public class ExceptionsTest {
connector.getLongitude();
connector.getTimestamp();
connector.getTimestamps();
connector.getTimestamps("Anything");
connector.getWeatherCategories();
connector.getWeatherDescriptions();
connector.getVisibility();
......@@ -62,6 +62,7 @@ public class ExceptionsTest {
connector.getLongitude();
connector.getTimestamp();
connector.getTimestamps();
connector.getTimestamps("Anything");
connector.getWeatherCategories(timestamp);
connector.getWeatherDescriptions(timestamp);
connector.getVisibility(timestamp);
......@@ -81,10 +82,12 @@ public class ExceptionsTest {
@Test
public void testAllowedOneCallMethods() {
OpenWeatherConnector connector = oneCall;
Date minutely = connector.getTimestamps("minutely").get(0);
connector.getLatitude();
connector.getLongitude();
connector.getTimestamp();
connector.getTimestamps();
connector.getTimestamps("Anything");
connector.getWeatherCategories();
connector.getWeatherDescriptions();
connector.getVisibility();
......@@ -99,6 +102,7 @@ public class ExceptionsTest {
connector.getOneHourSnowfall();
connector.getDewPoint();
connector.getUltravioletIndex();
connector.getMinutelyPrecipitation(minutely);
// pass
}
......@@ -128,8 +132,7 @@ public class ExceptionsTest {
@Test
public void testAllowedAirPollutionHistoryMethods() {
OpenWeatherConnector connector = airPollutionHistory;
List<Date> timestamps = connector.getTimestamps();
Date timestamp = timestamps.get(0);
Date timestamp = connector.getTimestamps().get(0);
connector.getAirQualityIndex(timestamp);
connector.getCarbonMonoxide(timestamp);
connector.getNitrogenDioxide(timestamp);
......@@ -181,6 +184,11 @@ public class ExceptionsTest {
fail(failMessage);
} catch (IllegalStateException ignored) {
}
try {
connector.getTimestamps("Anything");
fail(failMessage);
} catch (IllegalStateException ignored) {
}
try {
connector.getWeatherCategories();
fail(failMessage);
......@@ -406,6 +414,11 @@ public class ExceptionsTest {
fail(failMessage);
} catch (IllegalStateException ignored) {
}
try {
connector.getMinutelyPrecipitation(timestamp);
fail(failMessage);
} catch (IllegalStateException ignored) {
}
// pass
}
......@@ -569,6 +582,11 @@ public class ExceptionsTest {
fail(failMessage);
} catch (UnsupportedOperationException ignored) {
}
try {
connector.getMinutelyPrecipitation(timestamp);
fail(failMessage);
} catch (UnsupportedOperationException ignored) {
}
// pass
}
......@@ -737,6 +755,11 @@ public class ExceptionsTest {
fail(failMessage);
} catch (UnsupportedOperationException ignored) {
}
try {
connector.getMinutelyPrecipitation(timestamp);
fail(failMessage);
} catch (UnsupportedOperationException ignored) {
}
// pass
}
......@@ -1043,6 +1066,11 @@ public class ExceptionsTest {
fail(failMessage);
} catch (UnsupportedOperationException ignored) {
}
try {
connector.getMinutelyPrecipitation(timestamp);
fail(failMessage);
} catch (UnsupportedOperationException ignored) {
}
// pass
}
......@@ -1236,6 +1264,11 @@ public class ExceptionsTest {
fail(failMessage);
} catch (UnsupportedOperationException ignored) {
}
try {
connector.getMinutelyPrecipitation(timestamp);
fail(failMessage);
} catch (UnsupportedOperationException ignored) {
}
// pass
}
......@@ -1429,6 +1462,11 @@ public class ExceptionsTest {
fail(failMessage);
} catch (UnsupportedOperationException ignored) {
}
try {
connector.getMinutelyPrecipitation(timestamp);
fail(failMessage);
} catch (UnsupportedOperationException ignored) {
}
// pass
}
}
......@@ -7,6 +7,7 @@ import org.junit.Test;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import static org.junit.Assert.assertEquals;
......@@ -30,13 +31,32 @@ public class OneCall_WebsiteExampleTest {
}
@Test
public void testDateTime() {
public void testCurrentDateTime() {
// Date expectedValue = new Date(16183170400000L);
String expectedValue = "Tue Apr 13 07:30:40 CDT 2021";
Date actualValue = connector.getTimestamp();
assertEquals(expectedValue, actualValue.toString());
}
@Test
public void testListDateTimes() {
// List<Date> expectedMinutes = List.of(new Date(1618317060000L));
// List<Date> expectedHours = List.of(new Date(1618315200000L));
// List<Date> expectedDays = List.of(new Date(1618308000000L));
List<String> expectedMinutes = List.of("Tue Apr 13 07:31:00 CDT 2021");
List<String> expectedHours = List.of("Tue Apr 13 07:00:00 CDT 2021");
List<String> expectedDays = List.of("Tue Apr 13 05:00:00 CDT 2021");
List<String> actualMinutes = connector.getTimestamps("minutely")
.stream().map(Date::toString).collect(Collectors.toList());
List<String> actualHours = connector.getTimestamps("hourly")
.stream().map(Date::toString).collect(Collectors.toList());
List<String> actualDays = connector.getTimestamps("daily")
.stream().map(Date::toString).collect(Collectors.toList());
assertEquals(expectedMinutes, actualMinutes);
assertEquals(expectedHours, actualHours);
assertEquals(expectedDays, actualDays);
}
@Test
public void testWeather() {
OpenWeatherConnector.WeatherCategory expectedCategory = OpenWeatherConnector.WeatherCategory.RAIN;
......@@ -108,4 +128,12 @@ public class OneCall_WebsiteExampleTest {
assertEquals(expected1HourRain, actual1HourRain, 0.0001);
assertEquals(expected1HourSnow, actual1HourSnow, 0.0001);
}
@Test
public void testMinutelyPrecipitation() {
Date timestamp = connector.getTimestamps("minutely").get(0);
double expectedPrecipitation = 0.205;
double actualPrecipitation = connector.getMinutelyPrecipitation(timestamp);
assertEquals(expectedPrecipitation, actualPrecipitation, 0.0001);
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment