Skip to content

Commit 200d69a

Browse files
committed
feat: Forecast endpoint
1 parent df6bf48 commit 200d69a

2 files changed

Lines changed: 308 additions & 0 deletions

File tree

Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
package com.openmeteo.api
2+
3+
import com.openmeteo.api.common.Options
4+
import com.openmeteo.api.common.time.Date
5+
import com.openmeteo.api.common.time.Timezone
6+
import com.openmeteo.api.common.units.Unit
7+
import kotlinx.serialization.SerialName
8+
import kotlinx.serialization.Serializable
9+
import java.net.URL
10+
import com.openmeteo.api.common.Response as R
11+
import com.openmeteo.api.common.query.Query as Q
12+
13+
object Forecast {
14+
15+
val context = URL("https://api.open-meteo.com/v1/forecast")
16+
17+
@Serializable
18+
open class Query(
19+
override val latitude: Float,
20+
override val longitude: Float,
21+
override val daily: String? = null,
22+
override val hourly: String? = null,
23+
@SerialName("start_date")
24+
override val startDate: Date? = null,
25+
@SerialName("end_date")
26+
override val endDate: Date? = null,
27+
@SerialName("past_days")
28+
override val pastDays: Int? = null,
29+
@SerialName("forecast_days")
30+
override val forecastDays: Int? = null,
31+
@SerialName("current_weather")
32+
override val currentWeather: Boolean? = null,
33+
override val timezone: Timezone? = null,
34+
) : Q.Coordinate, Q.Daily, Q.Hourly, Q.TimeFormat, Q.DateRange,
35+
Q.PastDays, Q.ForecastDays, Q.CurrentWeather, Q.Timezone
36+
37+
@Serializable
38+
data class Response(
39+
override val latitude: Float,
40+
override val longitude: Float,
41+
override val utcOffsetSeconds: Int,
42+
override val timezone: Timezone,
43+
override val timezoneAbbreviation: String,
44+
override val generationtimeMs: Float,
45+
override val elevation: Float,
46+
override val dailyUnits: Map<String, Unit> = mapOf(),
47+
@SerialName("daily")
48+
override val dailyValues: Map<String, Array<Double?>> = mapOf(),
49+
override val hourlyUnits: Map<String, Unit> = mapOf(),
50+
@SerialName("hourly")
51+
override val hourlyValues: Map<String, Array<Double?>> = mapOf(),
52+
override val currentWeather: com.openmeteo.api.common.Response.CurrentWeather.CurrentWeather? = null,
53+
) : R.Coordinate, R.GenerationTimed, R.TimeZone, R.Elevation, R.Daily, R.Hourly, R.CurrentWeather
54+
55+
@Serializable
56+
object Daily : Options.Daily {
57+
const val weathercode="weathercode"
58+
const val temperature2mMax="temperature_2m_max"
59+
const val temperature2mMin="temperature_2m_min"
60+
const val apparentTemperatureMax="apparent_temperature_max"
61+
const val apparentTemperatureMin="apparent_temperature_min"
62+
const val sunrise="sunrise"
63+
const val sunset="sunset"
64+
const val uvIndexMax="uv_index_max"
65+
const val uvIndexClearSkyMax="uv_index_clear_sky_max"
66+
const val precipitationSum="precipitation_sum"
67+
const val rainSum="rain_sum"
68+
const val showersSum="showers_sum"
69+
const val snowfallSum="snowfall_sum"
70+
const val precipitationHours="precipitation_hours"
71+
const val precipitationProbabilityMax="precipitation_probability_max"
72+
const val windspeed10mMax="windspeed_10m_max"
73+
const val windgusts10mMax="windgusts_10m_max"
74+
const val winddirection10mDominant="winddirection_10m_dominant"
75+
const val shortwaveRadiationSum="shortwave_radiation_sum"
76+
const val et0FaoEvapotranspiration="et0_fao_evapotranspiration"
77+
}
78+
79+
@Serializable
80+
object Hourly : Options.Hourly {
81+
const val temperature2m="temperature_2m"
82+
const val relativehumidity2m="relativehumidity_2m"
83+
const val dewpoint2m="dewpoint_2m"
84+
const val apparentTemperature="apparent_temperature"
85+
const val precipitationProbability="precipitation_probability"
86+
const val precipitation="precipitation"
87+
const val rain="rain"
88+
const val showers="showers"
89+
const val snowfall="snowfall"
90+
const val snowDepth="snow_depth"
91+
const val weathercode="weathercode"
92+
const val pressureMsl="pressure_msl"
93+
const val surfacePressure="surface_pressure"
94+
const val cloudcover="cloudcover"
95+
const val cloudcoverLow="cloudcover_low"
96+
const val cloudcoverMid="cloudcover_mid"
97+
const val cloudcoverHigh="cloudcover_high"
98+
const val visibility="visibility"
99+
const val evapotranspiration="evapotranspiration"
100+
const val et0FaoEvapotranspiration="et0_fao_evapotranspiration"
101+
const val vaporPressureDeficit="vapor_pressure_deficit"
102+
const val windspeed10m="windspeed_10m"
103+
const val windspeed80m="windspeed_80m"
104+
const val windspeed120m="windspeed_120m"
105+
const val windspeed180m="windspeed_180m"
106+
const val winddirection10m="winddirection_10m"
107+
const val winddirection80m="winddirection_80m"
108+
const val winddirection120m="winddirection_120m"
109+
const val winddirection180m="winddirection_180m"
110+
const val windgusts10m="windgusts_10m"
111+
const val temperature80m="temperature_80m"
112+
const val temperature120m="temperature_120m"
113+
const val temperature180m="temperature_180m"
114+
const val soilTemperature0cm="soil_temperature_0cm"
115+
const val soilTemperature6cm="soil_temperature_6cm"
116+
const val soilTemperature18cm="soil_temperature_18cm"
117+
const val soilTemperature54cm="soil_temperature_54cm"
118+
const val soilMoisture01cm="soil_moisture_0_1cm"
119+
const val soilMoisture13cm="soil_moisture_1_3cm"
120+
const val soilMoisture39cm="soil_moisture_3_9cm"
121+
const val soilMoisture927cm="soil_moisture_9_27cm"
122+
const val soilMoisture2781cm="soil_moisture_27_81cm"
123+
const val uvIndex="uv_index"
124+
const val uvIndexClearSky="uv_index_clear_sky"
125+
const val isDay="is_day"
126+
const val cape="cape"
127+
const val freezinglevelHeight="freezinglevel_height"
128+
const val shortwaveRadiation="shortwave_radiation"
129+
const val directRadiation="direct_radiation"
130+
const val diffuseRadiation="diffuse_radiation"
131+
const val directNormalIrradiance="direct_normal_irradiance"
132+
const val terrestrialRadiation="terrestrial_radiation"
133+
const val shortwaveRadiationInstant="shortwave_radiation_instant"
134+
const val directRadiationInstant="direct_radiation_instant"
135+
const val diffuseRadiationInstant="diffuse_radiation_instant"
136+
const val directNormalIrradianceInstant="direct_normal_irradiance_instant"
137+
const val terrestrialRadiationInstant="terrestrial_radiation_instant"
138+
const val temperature1000hPa="temperature_1000hPa"
139+
const val temperature975hPa="temperature_975hPa"
140+
const val temperature950hPa="temperature_950hPa"
141+
const val temperature925hPa="temperature_925hPa"
142+
const val temperature900hPa="temperature_900hPa"
143+
const val temperature850hPa="temperature_850hPa"
144+
const val temperature800hPa="temperature_800hPa"
145+
const val temperature700hPa="temperature_700hPa"
146+
const val temperature600hPa="temperature_600hPa"
147+
const val temperature500hPa="temperature_500hPa"
148+
const val temperature400hPa="temperature_400hPa"
149+
const val temperature300hPa="temperature_300hPa"
150+
const val temperature250hPa="temperature_250hPa"
151+
const val temperature200hPa="temperature_200hPa"
152+
const val temperature150hPa="temperature_150hPa"
153+
const val temperature100hPa="temperature_100hPa"
154+
const val temperature70hPa="temperature_70hPa"
155+
const val temperature50hPa="temperature_50hPa"
156+
const val temperature30hPa="temperature_30hPa"
157+
const val relativehumidity1000hPa="relativehumidity_1000hPa"
158+
const val relativehumidity975hPa="relativehumidity_975hPa"
159+
const val relativehumidity950hPa="relativehumidity_950hPa"
160+
const val relativehumidity925hPa="relativehumidity_925hPa"
161+
const val relativehumidity900hPa="relativehumidity_900hPa"
162+
const val relativehumidity850hPa="relativehumidity_850hPa"
163+
const val relativehumidity800hPa="relativehumidity_800hPa"
164+
const val relativehumidity700hPa="relativehumidity_700hPa"
165+
const val relativehumidity600hPa="relativehumidity_600hPa"
166+
const val relativehumidity500hPa="relativehumidity_500hPa"
167+
const val relativehumidity400hPa="relativehumidity_400hPa"
168+
const val relativehumidity300hPa="relativehumidity_300hPa"
169+
const val relativehumidity250hPa="relativehumidity_250hPa"
170+
const val relativehumidity200hPa="relativehumidity_200hPa"
171+
const val relativehumidity150hPa="relativehumidity_150hPa"
172+
const val relativehumidity100hPa="relativehumidity_100hPa"
173+
const val relativehumidity70hPa="relativehumidity_70hPa"
174+
const val relativehumidity50hPa="relativehumidity_50hPa"
175+
const val relativehumidity30hPa="relativehumidity_30hPa"
176+
const val cloudcover1000hPa="cloudcover_1000hPa"
177+
const val cloudcover975hPa="cloudcover_975hPa"
178+
const val cloudcover950hPa="cloudcover_950hPa"
179+
const val cloudcover925hPa="cloudcover_925hPa"
180+
const val cloudcover900hPa="cloudcover_900hPa"
181+
const val cloudcover850hPa="cloudcover_850hPa"
182+
const val cloudcover800hPa="cloudcover_800hPa"
183+
const val cloudcover700hPa="cloudcover_700hPa"
184+
const val cloudcover600hPa="cloudcover_600hPa"
185+
const val cloudcover500hPa="cloudcover_500hPa"
186+
const val cloudcover400hPa="cloudcover_400hPa"
187+
const val cloudcover300hPa="cloudcover_300hPa"
188+
const val cloudcover250hPa="cloudcover_250hPa"
189+
const val cloudcover200hPa="cloudcover_200hPa"
190+
const val cloudcover150hPa="cloudcover_150hPa"
191+
const val cloudcover100hPa="cloudcover_100hPa"
192+
const val cloudcover70hPa="cloudcover_70hPa"
193+
const val cloudcover50hPa="cloudcover_50hPa"
194+
const val cloudcover30hPa="cloudcover_30hPa"
195+
const val windspeed1000hPa="windspeed_1000hPa"
196+
const val windspeed975hPa="windspeed_975hPa"
197+
const val windspeed950hPa="windspeed_950hPa"
198+
const val windspeed925hPa="windspeed_925hPa"
199+
const val windspeed900hPa="windspeed_900hPa"
200+
const val windspeed850hPa="windspeed_850hPa"
201+
const val windspeed800hPa="windspeed_800hPa"
202+
const val windspeed700hPa="windspeed_700hPa"
203+
const val windspeed600hPa="windspeed_600hPa"
204+
const val windspeed500hPa="windspeed_500hPa"
205+
const val windspeed400hPa="windspeed_400hPa"
206+
const val windspeed300hPa="windspeed_300hPa"
207+
const val windspeed250hPa="windspeed_250hPa"
208+
const val windspeed200hPa="windspeed_200hPa"
209+
const val windspeed150hPa="windspeed_150hPa"
210+
const val windspeed100hPa="windspeed_100hPa"
211+
const val windspeed70hPa="windspeed_70hPa"
212+
const val windspeed50hPa="windspeed_50hPa"
213+
const val windspeed30hPa="windspeed_30hPa"
214+
const val winddirection1000hPa="winddirection_1000hPa"
215+
const val winddirection975hPa="winddirection_975hPa"
216+
const val winddirection950hPa="winddirection_950hPa"
217+
const val winddirection925hPa="winddirection_925hPa"
218+
const val winddirection900hPa="winddirection_900hPa"
219+
const val winddirection850hPa="winddirection_850hPa"
220+
const val winddirection800hPa="winddirection_800hPa"
221+
const val winddirection700hPa="winddirection_700hPa"
222+
const val winddirection600hPa="winddirection_600hPa"
223+
const val winddirection500hPa="winddirection_500hPa"
224+
const val winddirection400hPa="winddirection_400hPa"
225+
const val winddirection300hPa="winddirection_300hPa"
226+
const val winddirection250hPa="winddirection_250hPa"
227+
const val winddirection200hPa="winddirection_200hPa"
228+
const val winddirection150hPa="winddirection_150hPa"
229+
const val winddirection100hPa="winddirection_100hPa"
230+
const val winddirection70hPa="winddirection_70hPa"
231+
const val winddirection50hPa="winddirection_50hPa"
232+
const val winddirection30hPa="winddirection_30hPa"
233+
const val geopotentialHeight1000hPa="geopotential_height_1000hPa"
234+
const val geopotentialHeight975hPa="geopotential_height_975hPa"
235+
const val geopotentialHeight950hPa="geopotential_height_950hPa"
236+
const val geopotentialHeight925hPa="geopotential_height_925hPa"
237+
const val geopotentialHeight900hPa="geopotential_height_900hPa"
238+
const val geopotentialHeight850hPa="geopotential_height_850hPa"
239+
const val geopotentialHeight800hPa="geopotential_height_800hPa"
240+
const val geopotentialHeight700hPa="geopotential_height_700hPa"
241+
const val geopotentialHeight600hPa="geopotential_height_600hPa"
242+
const val geopotentialHeight500hPa="geopotential_height_500hPa"
243+
const val geopotentialHeight400hPa="geopotential_height_400hPa"
244+
const val geopotentialHeight300hPa="geopotential_height_300hPa"
245+
const val geopotentialHeight250hPa="geopotential_height_250hPa"
246+
const val geopotentialHeight200hPa="geopotential_height_200hPa"
247+
const val geopotentialHeight150hPa="geopotential_height_150hPa"
248+
const val geopotentialHeight100hPa="geopotential_height_100hPa"
249+
const val geopotentialHeight70hPa="geopotential_height_70hPa"
250+
const val geopotentialHeight50hPa="geopotential_height_50hPa"
251+
const val geopotentialHeight30hPa="geopotential_height_30hPa"
252+
}
253+
254+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package com.openmeteo.api
2+
3+
import com.openmeteo.api.common.Options
4+
import com.openmeteo.api.common.http.Endpoint
5+
import com.openmeteo.api.common.query.City
6+
import com.openmeteo.api.common.time.Timezone
7+
import com.openmeteo.api.common.units.Unit
8+
import kotlin.test.Test
9+
import kotlin.test.assertContains
10+
import kotlin.test.assertEquals
11+
12+
class ForecastTest {
13+
14+
companion object {
15+
val forecast = Endpoint(Forecast.context)
16+
}
17+
18+
@Test
19+
fun `Amsterdam, with past day`() {
20+
val query = Forecast.Query(
21+
latitude = City.Amsterdam.latitude,
22+
longitude = City.Amsterdam.longitude,
23+
daily = Options.list(Forecast.Daily) { of(
24+
weathercode, sunrise, sunset, temperature2mMax, temperature2mMin
25+
) },
26+
timezone = Timezone.auto,
27+
pastDays = 1,
28+
)
29+
forecast.query<Forecast.Response, Forecast.Query>(query)
30+
.getOrThrow().run {
31+
assertEquals(52.38f, latitude)
32+
assertEquals(4.9f, longitude)
33+
// assertEquals(utcOffsetSeconds, 7200) // TODO: changes based on summer time?
34+
assertEquals("Europe/Amsterdam", timezone.id)
35+
assertEquals("CEST", timezoneAbbreviation)
36+
assertEquals(17f, elevation)
37+
assert(dailyUnits.equals(mapOf(
38+
"time" to Unit.UnixTime,
39+
"weathercode" to Unit.WeatherCode,
40+
"sunrise" to Unit.UnixTime,
41+
"sunset" to Unit.UnixTime,
42+
"temperature_2m_max" to Unit.Celsius,
43+
"temperature_2m_min" to Unit.Celsius,
44+
)))
45+
assertContains(dailyValues, "time")
46+
assertContains(dailyValues, "weathercode")
47+
assertContains(dailyValues, "sunrise")
48+
assertContains(dailyValues, "sunset")
49+
assertContains(dailyValues, "temperature_2m_max")
50+
assertContains(dailyValues, "temperature_2m_min")
51+
}
52+
}
53+
54+
}

0 commit comments

Comments
 (0)