Overview

SYNOP is a standardized format for reporting weather observations usually every hour. This vignette demonstrates how to work with SYNOP FM-12 meteorological messages using the climate package.

The package provides two complementary functions for handling SYNOP data:

  • synop_parser() — parse raw SYNOP message strings into structured data
  • meteo_ogimet(source = "synop") — download raw SYNOP messages from Ogimet web service and decode them automatically

The synop_parser() Function

The synop_parser() function decodes raw SYNOP messages into either a tidy data frame or a nested list structure.

Basic Usage - data frame output:

SYNOP messages should be provided as text vector of any length, e.g:

# Parse multiple messages
messages = c(
  "AAXX 01004 88889 12782 61506 10094 20047 30111 40197 53007 60001 81541",
  "AAXX 01006 12330 32782 61506 10094 20047 30111 40197 53007 60001 81541"
)

# Multiple messages as a data frame
df_multiple = synop_parser(messages, as_data_frame = TRUE)
df_multiple$source = NULL # remove raw message from output
# Display the results in a table
kable(t(df_multiple), caption = "Examplary results of parsing multiple SYNOP message into data frame")
Examplary results of parsing multiple SYNOP message into data frame
station_type AAXX AAXX
station_id 88889 12330
region III VI
obs_day 1 1
obs_hour 0 0
wind_unit KT KT
wind_estimated FALSE FALSE
visibility 40000 40000
cloud_cover 6 6
wind_direction 150 150
wind_speed 6 6
air_temperature 9.4 9.4
dewpoint_temperature 4.7 4.7
station_pressure 1011.1 1011.1
sea_level_pressure 1019.7 1019.7
pressure_tendency 3 3
pressure_change 0.7 0.7
precipitation_amount 0 NA
precipitation_time 12 NA
cloud_base_min 1500 1500
cloud_base_max 2000 2000
low_cloud_type 5 5
middle_cloud_type 4 4
high_cloud_type 1 1
low_cloud_amount 1 1
maximum_temperature NA NA
minimum_temperature NA NA
gust NA NA
cloudiness_height NA NA
sunshine_duration NA NA
snow_depth NA NA
snow_depth_state NA NA

Available Columns

  • When as_data_frame = TRUE, the returned data frame includes the following columns:

    • Identification and metadata: - station_type — station classification code - station_id — WMO station identifier - region — geographic region code - obs_day — observation day of month - obs_hour — observation hour (UTC)

    • Wind: - wind_unit — either “m/s” or “knots” - wind_estimated — whether wind is estimated - wind_direction — direction in degrees (0–360°) - wind_speed — speed in the reported unit

    • Temperature and moisture: - air_temperature — air temperature (°C) - dewpoint_temperature — dew point (°C)

    • Pressure: - station_pressure — station-level pressure (hPa) - sea_level_pressure — sea-level pressure (hPa) - pressure_tendency — pressure change indicator - pressure_change — 3-hour pressure change (hPa)

    • Clouds: - cloud_cover — total cloud cover (oktas, 0–8) - low_cloud_type — type of low clouds (Sc, St, Cu, Cb) - middle_cloud_type — type of middle clouds (Ac, As, Ns) - high_cloud_type — type of high clouds (Ci, Cc, Cs) - low_cloud_amount — cover of low clouds (oktas) - visibility — horizontal visibility (m) - cloud_base_min, cloud_base_max — cloud base height range (m)

    • Precipitation and other: - precipitation_amount — total precipitation (mm) - precipitation_time — precipitation period (hours) - maximum_temperature — daily maximum (°C, from Section 3) - minimum_temperature — daily minimum (°C, from Section 3) - gust — highest wind gust (in the message’s wind unit) - sunshine_duration — daily sunshine duration (hours) - snow_depth — total snow depth (cm) - snow_depth_state — descriptive snow/ground state

Nested List Output

For more granular access most of decoded field, use the default list output:

# Single message as a nested list
synop_code = messages[1]
decoded = synop_parser(synop_code)
str(decoded)
## List of 18
##  $ station_type           :List of 1
##   ..$ value: chr "AAXX"
##  $ obs_time               :List of 2
##   ..$ day :List of 1
##   .. ..$ value: int 1
##   ..$ hour:List of 1
##   .. ..$ value: int 0
##  $ wind_indicator         :List of 3
##   ..$ value    : int 4
##   ..$ unit     : chr "KT"
##   ..$ estimated: logi FALSE
##  $ station_id             :List of 1
##   ..$ value: chr "88889"
##  $ region                 :List of 1
##   ..$ value: chr "III"
##  $ precipitation_indicator:List of 3
##   ..$ value     : int 1
##   ..$ in_group_1: logi TRUE
##   ..$ in_group_3: logi FALSE
##  $ weather_indicator      :List of 2
##   ..$ value    : int 2
##   ..$ automatic: logi FALSE
##  $ lowest_cloud_base      :List of 6
##   ..$ min       : num 1500
##   ..$ max       : num 2000
##   ..$ quantifier: NULL
##   ..$ _table    : chr "1600"
##   ..$ _code     : int 7
##   ..$ unit      : chr "m"
##  $ visibility             :List of 6
##   ..$ value     : num 40000
##   ..$ quantifier: NULL
##   ..$ use90     : logi FALSE
##   ..$ _table    : chr "4377"
##   ..$ _code     : int 82
##   ..$ unit      : chr "m"
##  $ cloud_cover            :List of 5
##   ..$ value   : int 6
##   ..$ obscured: logi FALSE
##   ..$ unit    : chr "okta"
##   ..$ _table  : chr "2700"
##   ..$ _code   : int 6
##  $ surface_wind           :List of 2
##   ..$ direction:List of 6
##   .. ..$ value        : num 150
##   .. ..$ varAllUnknown: logi FALSE
##   .. ..$ calm         : logi FALSE
##   .. ..$ _table       : chr "0877"
##   .. ..$ _code        : int 15
##   .. ..$ unit         : chr "deg"
##   ..$ speed    :List of 2
##   .. ..$ value: int 6
##   .. ..$ unit : chr "KT"
##  $ air_temperature        :List of 2
##   ..$ value: num 9.4
##   ..$ unit : chr "Celsius"
##  $ dewpoint_temperature   :List of 2
##   ..$ value: num 4.7
##   ..$ unit : chr "Celsius"
##  $ station_pressure       :List of 2
##   ..$ value: num 1011
##   ..$ unit : chr "hPa"
##  $ sea_level_pressure     :List of 2
##   ..$ value: num 1020
##   ..$ unit : chr "hPa"
##  $ pressure_tendency      :List of 2
##   ..$ tendency:List of 1
##   .. ..$ value: int 3
##   ..$ change  :List of 2
##   .. ..$ value: num 0.7
##   .. ..$ unit : chr "hPa"
##  $ precipitation_s1       :List of 2
##   ..$ amount         :List of 6
##   .. ..$ value     : int 0
##   .. ..$ quantifier: NULL
##   .. ..$ trace     : logi FALSE
##   .. ..$ _table    : chr "3590"
##   .. ..$ _code     : int 0
##   .. ..$ unit      : chr "mm"
##   ..$ time_before_obs:List of 4
##   .. ..$ value : num 12
##   .. ..$ unit  : chr "h"
##   .. ..$ _table: chr "4019"
##   .. ..$ _code : int 1
##  $ cloud_types            :List of 4
##   ..$ low_cloud_type   :List of 1
##   .. ..$ value: int 5
##   ..$ middle_cloud_type:List of 1
##   .. ..$ value: int 4
##   ..$ high_cloud_type  :List of 1
##   .. ..$ value: int 1
##   ..$ low_cloud_amount :List of 5
##   .. ..$ value   : int 1
##   .. ..$ obscured: logi FALSE
##   .. ..$ unit    : chr "okta"
##   .. ..$ _table  : chr "2700"
##   .. ..$ _code   : int 1

To parse multiple messages and keep each as a separate list element:

# Returns a list of two decoded messages
decoded_list = synop_parser(messages, simplify = FALSE)

# Access the first message
decoded_list[[1]]

Country-Specific Decoding

Some SYNOP groups (e.g., precipitation indicators) are country-specific. Pass the country parameter to adjust decoding:

# Parse with Russia-specific precipitation decoding
decoded_ru = synop_parser(synop_code, country = "RU", as_data_frame = TRUE)

# Compare with default
decoded_default = synop_parser(synop_code, as_data_frame = TRUE)

The meteo_ogimet() Function — SYNOP Backend

The meteo_ogimet() function (with source = "synop") downloads SYNOP messages from Ogimet and automatically decodes them using parser().

Station Mode: Single or Multiple Stations

Fetch SYNOP data from OGIMET service for one or more WMO station IDs:

# can be used with multiple stations:
two_stations = meteo_ogimet(
  source  = "synop",
  station = c(12330, 12375),
  date    = c("2024-01-01", "2024-01-10")
)
## station: 12330
## http://www.ogimet.com/cgi-bin/getsynop?block=12330&begin=202401010000&end=202401102359
## Downloaded 240 SYNOP messages for: 12330
## station: 12375
## http://www.ogimet.com/cgi-bin/getsynop?block=12375&begin=202401010000&end=202401102359
## Downloaded 240 SYNOP messages for: 12375
kable(head(two_stations))
date station t2m dpt2m rel_hum tmax tmin wd ws gust press slp press_tend precip Nt Nh N_base insol visibility snow
2024-01-01 00:00:00 12330 3.1 2.2 93.8 NA NA 160 1 NA 995.6 1006.6 -0.2 0 8 7 1000 NA 1200 NA
2024-01-01 01:00:00 12330 2.7 1.8 93.8 NA NA 200 1 NA 995.7 1006.7 -0.2 NA 8 4 1500 NA 1000 NA
2024-01-01 02:00:00 12330 2.5 1.8 95.1 NA NA 230 2 NA 995.6 1006.6 -0.3 NA 8 NA NA NA 4000 NA
2024-01-01 03:00:00 12330 3.2 2.2 93.2 NA NA 220 3 NA 995.5 1006.5 -0.1 NA 8 3 1000 NA 7000 NA
2024-01-01 04:00:00 12330 3.3 2.1 91.8 NA NA 220 2 NA 995.3 1006.3 -0.4 NA 8 3 1000 NA 9000 NA
2024-01-01 05:00:00 12330 3.4 2.4 93.2 NA NA 200 2 NA 995.0 1006.0 -0.6 NA 8 NA NA NA 9000 NA

Country mode: all stations in a country

Fetch SYNOP data for all Ogimet stations in a country for a given time range:

# All Polish stations for a single day
poland = meteo_ogimet(
  source       = "synop",
  country_name = "Poland",
  date         = c("2024-01-15", "2024-01-15")
)
## Downloading country: Poland
## http://www.ogimet.com/cgi-bin/getsynop?begin=202401150000&end=202401152359&state=Poland
## Could not retrieve data for: Poland
## No SYNOP data returned for: Poland
head(poland)
## NULL

Simplified vs. full data frame output

By default, meteo_ogimet() returns a simplified data frame with the most commonly used variables. To get all decoded SYNOP fields, use simplified = FALSE:

# Full synop_parser output
full = meteo_ogimet(
  source     = "synop",
  station    = 12330,
  date       = c("2024-01-01", "2024-01-05"),
  simplified = FALSE
)
## station: 12330
## http://www.ogimet.com/cgi-bin/getsynop?block=12330&begin=202401010000&end=202401052359
## Could not retrieve data for: 12330
## No SYNOP data returned for: 12330
head(full)
## NULL

To obtain both the simplified and full data frames in one call, use return_list = TRUE:

result = meteo_ogimet(
  source      = "synop",
  station     = 12330,
  date        = c("2024-01-01", "2024-01-05"),
  return_list = TRUE
)
# Compact 20-column view
names(result$data)
# Full 30+ column parser output
names(result$full)

Notes and Limitations

  • Ogimet server limits: The Ogimet server caps responses at 200,000 rows. If a date range would exceed this, the function automatically splits the range and recursively fetches each half.
  • Station delays: When fetching multiple stations in station mode, a 20-second delay is inserted between requests to avoid overloading the Ogimet server.
  • Missing observations: Not all SYNOP variables are reported at all times. Missing fields are returned as NA.
  • Historical data: Ogimet typically provides historical SYNOP data since approx. 1999/2000; availability varies by station and country.

See Also

  • Daily and hourly OGIMET data via the HTML backend: meteo_ogimet(source = "html")
  • WMO SYNOP documentation for FM-12: FM 12-XIII Ext. SYNOP