Getting Weather Data
There are two main entry paths in PlantMeteo:
- start with
get_weatherif you have coordinates and dates but no cleaned file yet - start with
read_weatherif you already have weather data from stations, archives, or project pipelines
Path 1: Get Weather From An API
This is the fastest route when downloading weather is the hard part.
using PlantMeteo
using Dates
period = Date(2025, 7, 1):Day(1):Date(2025, 7, 2)
api_weather = get_weather(48.8566, 2.3522, period; api = PlantMeteo.DemoAPI())
api_weather[1:4]| TimeStepTable{Atmosphere{(:date, :duration,...}(4 x 22): | ||||||||||||||||||||||
| date | duration | T | Wind | P | Rh | Precipitations | Cₐ | e | eₛ | VPD | ρ | λ | γ | ε | Δ | clearness | Ri_SW_f | Ri_PAR_f | Ri_NIR_f | Ri_TIR_f | Ri_custom_f | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| DateTime | Hour | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | |
| 1 | 2025-07-01T00:00:00 | 1 hour | 20.0 | 1.3 | 101.3 | 0.65 | 0.0 | 415.0 | 1.52555 | 2.347 | 0.821448 | 1.20379 | 2.4537e6 | 0.0672368 | 0.584806 | 0.145734 | Inf | 0.0 | Inf | Inf | Inf | Inf |
| 2 | 2025-07-01T01:00:00 | 1 hour | 21.2941 | 1.29659 | 101.3 | 0.611177 | 0.0 | 415.0 | 1.5535 | 2.54181 | 0.988315 | 1.19849 | 2.45064e6 | 0.0673208 | 0.585956 | 0.156273 | Inf | 0.0 | Inf | Inf | Inf | Inf |
| 3 | 2025-07-01T02:00:00 | 1 hour | 22.5 | 1.2866 | 101.3 | 0.575 | 0.0 | 415.0 | 1.57317 | 2.73596 | 1.16278 | 1.19361 | 2.44779e6 | 0.0673992 | 0.586667 | 0.166668 | Inf | 0.0 | Inf | Inf | Inf | Inf |
| 4 | 2025-07-01T03:00:00 | 1 hour | 23.5355 | 1.27071 | 101.3 | 0.543934 | 0.0 | 415.0 | 1.58443 | 2.9129 | 1.32847 | 1.18944 | 2.44534e6 | 0.0674667 | 0.586972 | 0.176056 | Inf | 0.0 | Inf | Inf | Inf | Inf |
PlantMeteo.DemoAPI() is only for tests, demos, and documentation. It is not an actual weather service. The default real backend is OpenMeteo().
This function can return any type you want via the sink keyword, which is a function that transforms the full weather table into a derived object. By default, sink is the identity function, but you could use DataFrame instead.
You can also use it to get a summary or a custom struct instead of the full table. For example, you could use sink to get a summary of the weather data like this:
summary = get_weather(
48.8566,
2.3522,
period;
api = PlantMeteo.DemoAPI(),
sink = x -> (
nsteps = length(x),
first_date = x[1].date,
mean_temperature = round(sum(x.T) / length(x), digits = 2),
)
)(nsteps = 48, first_date = DateTime("2025-07-01T00:00:00"), mean_temperature = 20.4)summary.nsteps48summary.first_date2025-07-01T00:00:00summary.mean_temperature20.4Using The Built-In Open-Meteo Backend
In normal use, replace PlantMeteo.DemoAPI() with OpenMeteo():
using PlantMeteo, Dates
period = Date(2025, 7, 1):Day(1):Date(2025, 7, 3)
weather = get_weather(48.8566, 2.3522, period; api=OpenMeteo())Use this path first when:
- you do not already have trusted local weather files
- you need a quick forecast or a recent historical series
- you want a consistent hourly schema without writing provider-specific glue code
See Open-Meteo Guide for why Open-Meteo is a good default and when to validate against station data.
Path 2: Read And Standardize Local Files
Use read_weather when you already have weather data but need to map source-specific names and units into PlantMeteo variables.
file = joinpath(dirname(dirname(pathof(PlantMeteo))), "test", "data", "meteo.csv")
file_weather = read_weather(
file,
:temperature => :T,
:relativeHumidity => (x -> x ./ 100) => :Rh,
:wind => :Wind,
:atmosphereCO2_ppm => :Cₐ,
date_format = DateFormat("yyyy/mm/dd")
)| TimeStepTable{Atmosphere{(:date, :duration,...}(3 x 29): | |||||||||||||||||||||||||||||
| date | duration | T | Wind | P | Rh | Precipitations | Cₐ | e | eₛ | VPD | ρ | λ | γ | ε | Δ | clearness | Ri_SW_f | Ri_PAR_f | Ri_NIR_f | Ri_TIR_f | Ri_custom_f | hour_start | hour_end | temperature | relativeHumidity | Re_SW_f | wind | atmosphereCO2_ppm | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| DateTime | Dates.CompoundPeriod | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Time | Time | Float64 | Float64 | Float64 | Float64 | Float64 | |
| 1 | 2016-06-12T12:00:00 | 30 minutes | 25.0 | 1.0 | 101.325 | 0.6 | 0.0 | 380.0 | 1.90812 | 3.1802 | 1.27208 | 1.18389 | 2.44188e6 | 0.0675791 | 0.602345 | 0.190095 | 0.75 | Inf | Inf | Inf | Inf | Inf | 12:00:00 | 12:30:00 | 25.0 | 60.0 | 500.0 | 1.0 | 380.0 |
| 2 | 2016-06-12T12:30:00 | 30 minutes | 26.0 | 1.5 | 101.325 | 0.62 | 0.0 | 380.0 | 2.09238 | 3.37481 | 1.28243 | 1.17993 | 2.43951e6 | 0.0676446 | 0.610038 | 0.200215 | 0.75 | Inf | Inf | Inf | Inf | Inf | 12:30:00 | 13:00:00 | 26.0 | 62.0 | 500.0 | 1.5 | 380.0 |
| 3 | 2016-06-12T13:00:00 | 30 minutes | 25.3 | 1.5 | 101.325 | 0.58 | 0.0 | 380.0 | 1.87776 | 3.23752 | 1.35976 | 1.1827 | 2.44117e6 | 0.0675987 | 0.60088 | 0.193085 | 0.75 | Inf | Inf | Inf | Inf | Inf | 13:00:00 | 13:30:00 | 25.3 | 58.0 | 500.0 | 1.5 | 380.0 |
length(file_weather)3file_weather[1].date2016-06-12T12:00:00file_weather[1].T25.0PlantMeteo also handles legacy date encodings where only the first row contains the date and later rows must be forward-filled:
legacy = mktempdir() do tmp
path = joinpath(tmp, "legacy_meteo.csv")
write(path, """
date;hour_start;hour_end;temperature;relativeHumidity;wind;clearness
2016/06/12;08:30:00;09:00:00;25;60;1.0;0.6
;09:00:00;09:30:00;25;60;1.0;0.6
""")
read_weather(
path,
:temperature => :T,
:relativeHumidity => (x -> x ./ 100) => :Rh,
:wind => :Wind,
date_formats = (DateFormat("yyyy/mm/dd"), DateFormat("yyyy-mm-dd")),
forward_fill_date = true,
)
end| TimeStepTable{Atmosphere{(:date, :duration,...}(2 x 27): | |||||||||||||||||||||||||||
| date | duration | T | Wind | P | Rh | Precipitations | Cₐ | e | eₛ | VPD | ρ | λ | γ | ε | Δ | clearness | Ri_SW_f | Ri_PAR_f | Ri_NIR_f | Ri_TIR_f | Ri_custom_f | hour_start | hour_end | temperature | relativeHumidity | wind | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| DateTime | Dates.CompoundPeriod | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Time | Time | Int64 | Int64 | Float64 | |
| 1 | 2016-06-12T08:30:00 | 30 minutes | 25.0 | 1.0 | 101.325 | 0.6 | 0.0 | 400.0 | 1.90812 | 3.1802 | 1.27208 | 1.18389 | 2.44188e6 | 0.0675791 | 0.602345 | 0.190095 | 0.6 | Inf | Inf | Inf | Inf | Inf | 08:30:00 | 09:00:00 | 25 | 60 | 1.0 |
| 2 | 2016-06-12T09:00:00 | 30 minutes | 25.0 | 1.0 | 101.325 | 0.6 | 0.0 | 400.0 | 1.90812 | 3.1802 | 1.27208 | 1.18389 | 2.44188e6 | 0.0675791 | 0.602345 | 0.190095 | 0.6 | Inf | Inf | Inf | Inf | Inf | 09:00:00 | 09:30:00 | 25 | 60 | 1.0 |
legacy.date[1]2016-06-12T08:30:00legacy.date[2]2016-06-12T09:00:00Use this path first when:
- you already have station or archive files
- you need to preserve curated local data instead of re-downloading
- the main challenge is column naming, units, or date parsing rather than data acquisition
Choosing Between The Two
- Start with
get_weatherif your problem is getting weather data in the first place. - Start with
read_weatherif your problem is standardizing weather data you already own. - After either path, the downstream workflow is the same: inspect the table, aggregate with
to_daily, sample withsample_weather, or export withwrite_weather.