diff --git a/NAMESPACE b/NAMESPACE index 1cd1648..78a985d 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -7,5 +7,6 @@ export(az_daily) export(az_heat) export(az_hourly) export(az_lw15min) +export(az_lwdaily) importFrom(magrittr,"%>%") importFrom(rlang,.data) diff --git a/NEWS.md b/NEWS.md index 0860530..8e228fa 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,6 @@ # azmetr (development version) +- Added function `az_lwdaily()` for downloading daily leaf wetness data, which now are available via the API - Added function `az_lw15min()` for downloading 15-minute (a.k.a. "real-time") leaf wetness data, which now are available via the API - Added function `az_15min()` for downloading 15-minute (a.k.a. "real-time") data, which now are available via the API diff --git a/R/az_15min.R b/R/az_15min.R index 8a96cb4..e90c453 100755 --- a/R/az_15min.R +++ b/R/az_15min.R @@ -1,7 +1,8 @@ #' Retrieve 15-minute Weather Data from AZMet #' #' Retrieves 15-minute data from the AZMet (Arizona Meteorological Network) API. -#' For a list of weather stations and their locations see [station_info]. +#' For a list of weather stations and their locations see [station_info], or +#' visit https://azmet.arizona.edu/about. #' #' @param station_id Station ID can be supplied as numeric vector (e.g. #' `station_id = c(8, 37)`) or as character vector with the prefix "az" and @@ -16,7 +17,7 @@ #' Defaults to the current date and time if left blank and `start_date_time` #' is specified. #' @details If neither `start_date_time` nor `end_date_time` are supplied, the -#' most recent date-time of data will be returned. If only `start_date_time` +#' most recent datetime of data will be returned. If only `start_date_time` #' is supplied, then `end_date_time` defaults to the current time. Supplying #' only `end_date_time` will result in an error. #' @note If `station_id` is supplied as a vector, multiple successive calls to @@ -24,9 +25,9 @@ #' the stations by leaving `station_id` blank and subsetting the resulting #' dataframe. Only the most recent 48 hours of 15-minute data are stored in #' the AZMet API. -#' @return a tibble. For units and other metadata, see +#' @return A tibble. For units and other metadata, see #' -#' @seealso [az_daily()], [az_heat()], [az_hourly()], [az_lw15min()] +#' @seealso [az_daily()], [az_heat()], [az_hourly()], [az_lw15min()], [az_lwdaily()] #' @source #' @importFrom rlang .data #' @export @@ -71,7 +72,7 @@ az_15min <- function(station_id = NULL, start_date_time = NULL, end_date_time = # Query API ------------------------------------------------------------------ if (is.null(start_date_time) & is.null(end_date_time)) { - message("Querying most recent date-time of 15-minute data ...") + message("Querying most recent datetime of 15-minute data ...") } else { message( "Querying data from ", format(params$start, "%Y-%m-%d %H:%M:%S")," through ", format(params$end, "%Y-%m-%d %H:%M:%S"), " ..." @@ -110,7 +111,7 @@ az_15min <- function(station_id = NULL, start_date_time = NULL, end_date_time = } if (nrow(out) == 0) { - warning("No data retrieved from API.") + warning("No data retrieved from API") # Return 0x0 tibble return(tibble::tibble()) } diff --git a/R/az_add_units.R b/R/az_add_units.R index 996b344..29963e8 100644 --- a/R/az_add_units.R +++ b/R/az_add_units.R @@ -3,9 +3,9 @@ #' Assigns correct units to the output of `az_hourly()`, `az_daily()`, and #' `az_heat()` using the `units` package. #' -#' @param x a tibble output by [az_hourly()], [az_daily()], or [az_heat()] +#' @param x A tibble output by [az_hourly()], [az_daily()], or [az_heat()] #' -#' @return a tibble with columns of class "units" +#' @return A tibble with columns of class "units" #' @export #' #' @examples diff --git a/R/az_daily.R b/R/az_daily.R index 7bb2232..b334475 100644 --- a/R/az_daily.R +++ b/R/az_daily.R @@ -1,31 +1,35 @@ #' Retrieve Daily Weather Data from AZMET #' #' Retrieves daily data from the Arizona Meteorological Network API. For a list -#' of weather stations and their locations see [station_info]. +#' of weather stations and their locations see [station_info], or visit +#' https://azmet.arizona.edu/about. #' #' @param station_id station ID can be supplied as numeric vector (e.g. -#' `station_id = c(8, 37)`) or as character vector with the prefix "az" and 2 -#' digits (e.g. `station_id = c("az08", "az37")`) If left blank data for all -#' stations will be returned +#' `station_id = c(8, 37)`) or as character vector with the prefix "az" and +#' two digits (e.g. `station_id = c("az08", "az37")`). If left blank, data for all +#' stations will be returned. #' @param start_date A length-1 vector of class Date, POSIXct, or character in -#' YYYY-MM-DD format. Will be rounded **down** to the nearest day if more -#' precision is supplied. +#' YYYY-MM-DD format. Will be rounded **down** to the nearest day if more +#' precision is supplied. Defaults to the day before the current date (i.e., +#' the most recent complete day) if left blank. #' @param end_date A length-1 vector of class Date, POSIXct, or character in -#' YYYY-MM-DD format. Will be rounded **down** to the nearest day if more -#' precision is supplied. Defaults to the current date if left blank. +#' YYYY-MM-DD format. Will be rounded **down** to the nearest day if more +#' precision is supplied. Defaults to the day before the current date (i.e., +#' the most recent complete day) if left blank. #' @details If neither `start_date` nor `end_date` are supplied, the most recent -#' day of data will be returned. If only `start_date` is supplied, then the -#' end date defaults to the current date. Supplying only `end_date` will +#' day of data will be returned. If only `start_date` is supplied, then the +#' end date defaults to the day before the current date (i.e., +#' the most recent complete day). Supplying only `end_date` will #' result in an error. #' @note If `station_id` is supplied as a vector, multiple successive calls to #' the API will be made. You may find better performance getting data for all #' the stations by leaving `station_id` blank and subsetting the resulting #' dataframe. Requests for data from all stations for more than 6-12 months #' may take considerable time. -#' @return a tibble. For units and other metadata, see -#' -#' @seealso [az_15min()], [az_heat()], [az_hourly()], [az_lw15min()] -#' @source +#' @return A tibble. For units and other metadata, see +#' +#' @seealso [az_15min()], [az_heat()], [az_hourly()], [az_lw15min()], [az_lwdaily()] +#' @source #' #' @importFrom rlang .data #' @export @@ -43,18 +47,31 @@ #' az_daily(start_date = "2022-09-25") #' az_daily(start_date = "2022-09-25", end_date = "2022-09-26") #' } -#' + + az_daily <- function(station_id = NULL, start_date = NULL, end_date = NULL) { - #TODO: check for valid station IDs + # TODO: check for valid station IDs check_internet() + if(!is.null(end_date) & is.null(start_date)) { stop("If you supply `end_date`, you must also supply `start_date`") } + params <- - parse_params(station_id = station_id, start = start_date, end = end_date) + parse_params( + station_id = station_id, + start = start_date, + end = end_date, + hour = FALSE, + real_time = FALSE + ) + + tz = "America/Phoenix" + + + # Query API ----------------------------------------------------------------- - # Query API -------------------------------------------- if (is.null(start_date) & is.null(end_date)) { message("Querying data from ", params$start) } else { @@ -63,42 +80,48 @@ az_daily <- function(station_id = NULL, start_date = NULL, end_date = NULL) { if (length(station_id) <= 1) { out <- - retrieve_data(params$station_id, - params$start_f, - params$time_interval, - endpoint = "daily") + retrieve_data( + params$station_id, + params$start_f, + params$time_interval, + endpoint = "daily" + ) } else if (length(station_id) > 1) { out <- purrr::map_df( params$station_id, function(x) { - retrieve_data(x, - params$start_f, - params$time_interval, - endpoint = "daily") + retrieve_data( + x, + params$start_f, + params$time_interval, + endpoint = "daily" + ) } ) } if (nrow(out) == 0) { warning("No data retrieved from API") - #return 0x0 tibble for type consistency + # Return 0x0 tibble for type consistency return(tibble::tibble()) } - #Check if any data is missing + # Check if any data are missing n_obs <- out %>% dplyr::summarise(n = dplyr::n(), .by = dplyr::all_of("meta_station_id")) %>% dplyr::filter(.data$n < as.numeric(lubridate::period(params$time_interval), "day") + 1) if (nrow(n_obs) != 0 | # Also warn if the missing data is just at the end - lubridate::ymd(max(out$datetime), tz = "America/Phoenix") < params$end) { - warning("Some requested data were unavailable") + lubridate::ymd(max(out$datetime), tz = tz) < params$end) { + warning("Some requested data were unavailable.") } - # Wrangle output ---------------------------------------------------------- + + # Wrangle output ------------------------------------------------------------- + out <- out %>% - #move metadata to beginning + # Move metadata to beginning dplyr::select(dplyr::starts_with("meta_"), dplyr::everything()) %>% dplyr::mutate(dplyr::across( c(-"meta_station_id", -"meta_station_name", -"datetime", -"wind_2min_timestamp"), @@ -106,7 +129,7 @@ az_daily <- function(station_id = NULL, start_date = NULL, end_date = NULL) { )) %>% dplyr::filter(.data$meta_station_id != "az99") %>% dplyr::mutate(datetime = lubridate::ymd(.data$datetime)) %>% - #convert NAs + # Convert NAs dplyr::mutate( dplyr::across( tidyselect::where(is.numeric), @@ -124,7 +147,7 @@ az_daily <- function(station_id = NULL, start_date = NULL, end_date = NULL) { dplyr::mutate( wind_2min_timestamp = lubridate::with_tz( lubridate::parse_date_time(.data$wind_2min_timestamp, orders = "ymdHMSz"), - tzone = "America/Phoenix" + tzone = tz ) ) diff --git a/R/az_heat.R b/R/az_heat.R index a6b1194..6250e86 100644 --- a/R/az_heat.R +++ b/R/az_heat.R @@ -1,9 +1,10 @@ #' Retrieve Accumulated Heat Units and Evapotranspiration #' #' Retrieves accumulated heat units and reference evapotranspiration units from -#' the Arizona Meteorological Network API. By default, returned values are +#' the Arizona Meteorological Network API. By default, returned values are #' cumulative since January 1 of the current year. For a list of weather -#' stations and their locations see [station_info]. +#' stations and their locations see [station_info], or visit +#' https://azmet.arizona.edu/about. #' #' @param station_id station ID can be supplied as numeric vector (e.g. #' `station_id = c(8, 37)`) or as character vector with the prefix "az" and 2 @@ -24,10 +25,10 @@ #' the API will be made. You may find better performance getting data for all #' the stations by leaving `station_id` blank and subsetting the resulting #' dataframe. -#' @return a tibble. For units and other metadata, see -#' -#' @seealso [az_15min()], [az_daily()], [az_hourly()], [az_lw15min()] -#' @source +#' @return A tibble. For units and other metadata, see +#' +#' @seealso [az_15min()], [az_daily()], [az_hourly()], [az_lw15min()], [az_lwdaily()] +#' @source #' @importFrom rlang .data #' @export #' @@ -52,8 +53,8 @@ #' az_heat <- function(station_id = NULL, start_date = NULL, end_date = NULL) { tz <- "America/Phoenix" - #TODO: document output columns or link to API docs if appropriate - #TODO: check for valid station IDs + # TODO: document output columns or link to API docs if appropriate + # TODO: check for valid station IDs check_internet() # If no start date supplied, default is Jan 1 of current year. if (is.null(start_date)) { diff --git a/R/az_hourly.R b/R/az_hourly.R index e81e40c..c11ac3f 100644 --- a/R/az_hourly.R +++ b/R/az_hourly.R @@ -1,11 +1,12 @@ #' Retrieve Hourly Weather Data #' #' Retrieves hourly weather data from the Arizona Meteorological Network API. -#' For a list of weather stations and their locations see [station_info]. +#' For a list of weather stations and their locations see [station_info], or +#' visit https://azmet.arizona.edu/about. #' #' @param station_id station ID can be supplied as numeric vector (e.g. #' `station_id = c(8, 37)`) or as character vector with the prefix "az" and 2 -#' digits (e.g. `station_id = c("az08", "az37")`) If left blank data for all +#' digits (e.g. `station_id = c("az08", "az37")`) If left blank, data for all #' stations will be returned #' @param start_date_time A length-1 vector of class POSIXct or character in #' YYYY-MM-DD HH format, in AZ time. Will be rounded **down** to the nearest @@ -26,10 +27,10 @@ #' the stations by leaving `station_id` blank and subsetting the resulting #' dataframe. Requests for data from all stations for more than 10-15 days may #' take considerable time. -#' @return a tibble. For units and other metadata, see -#' -#' @seealso [az_15min()], [az_daily()], [az_heat()], [az_lw15min()] -#' @source +#' @return A tibble. For units and other metadata, see +#' +#' @seealso [az_15min()], [az_daily()], [az_heat()], [az_lw15min()], [az_lwdaily()] +#' @source #' @importFrom rlang .data #' @export #' @@ -49,7 +50,7 @@ #' az_hourly <- function(station_id = NULL, start_date_time = NULL, end_date_time = NULL) { - #TODO: check for valid station IDs + # TODO: check for valid station IDs check_internet() if(!is.null(end_date_time) & is.null(start_date_time)) { stop("If you supply `end_date_time`, you must also supply `start_date_time`") diff --git a/R/az_lw15min.R b/R/az_lw15min.R index de0e750..464310d 100644 --- a/R/az_lw15min.R +++ b/R/az_lw15min.R @@ -1,8 +1,9 @@ #' Retrieve 15-minute Leaf Wetness Data from AZMet #' #' Retrieves 15-minute leaf-wetness data from the AZMet (Arizona Meteorological -#' Network) API. Currently, these data only are available from stations in the -#' Yuma area. For a list of stations and their locations see [station_info]. +#' Network) API. Currently, these data only are available from weather stations +#' in the Yuma area. For a list of stations and their locations see +#' [station_info], or visit https://azmet.arizona.edu/about. #' #' @param station_id Station ID can be supplied as numeric vector (e.g. #' `station_id = c(8, 37)`) or as character vector with the prefix "az" and @@ -17,7 +18,7 @@ #' Defaults to the current date and time if left blank and `start_date_time` #' is specified. #' @details If neither `start_date_time` nor `end_date_time` are supplied, the -#' most recent date-time of data will be returned. If only `start_date_time` +#' most recent datetime of data will be returned. If only `start_date_time` #' is supplied, then `end_date_time` defaults to the current time. Supplying #' only `end_date_time` will result in an error. #' @note If `station_id` is supplied as a vector, multiple successive calls to @@ -25,9 +26,9 @@ #' the stations by leaving `station_id` blank and subsetting the resulting #' dataframe. Only the most recent 48 hours of 15-minute data are stored in #' the AZMet API. -#' @return a tibble. For units and other metadata, see +#' @return A tibble. For units and other metadata, see #' -#' @seealso [az_15min()], [az_daily()], [az_heat()], [az_hourly()] +#' @seealso [az_15min()], [az_daily()], [az_heat()], [az_hourly()], [az_lwdaily()] #' @source #' @importFrom rlang .data #' @export @@ -72,7 +73,7 @@ az_lw15min <- function(station_id = NULL, start_date_time = NULL, end_date_time # Query API ------------------------------------------------------------------ if (is.null(start_date_time) & is.null(end_date_time)) { - message("Querying most recent date-time of leaf wetness 15-minute data ...") + message("Querying most recent datetime of leaf wetness 15-minute data ...") } else { message( "Querying data from ", format(params$start, "%Y-%m-%d %H:%M:%S")," through ", format(params$end, "%Y-%m-%d %H:%M:%S"), " ..." @@ -111,7 +112,7 @@ az_lw15min <- function(station_id = NULL, start_date_time = NULL, end_date_time } if (nrow(out) == 0) { - warning("No data retrieved from API.") + warning("No data retrieved from API") # Return 0x0 tibble return(tibble::tibble()) } diff --git a/R/az_lwdaily.R b/R/az_lwdaily.R new file mode 100644 index 0000000..e412b21 --- /dev/null +++ b/R/az_lwdaily.R @@ -0,0 +1,146 @@ +#' Retrieve Daily Leaf Wetness Data from AZMet +#' +#' Retrieves daily leaf wetness data from the Arizona Meteorological Network +#' API. Currently, these data only are available from weather stations in the +#' Yuma area. For a list of stations and their locations see [station_info], or +#' visit https://azmet.arizona.edu/about. +#' +#' @param station_id station ID can be supplied as numeric vector (e.g. +#' `station_id = c(8, 37)`) or as character vector with the prefix "az" and +#' two digits (e.g. `station_id = c("az08", "az37")`). If left blank, data for +#' all stations will be returned. +#' @param start_date A length-1 vector of class Date, POSIXct, or character in +#' YYYY-MM-DD format. Will be rounded **down** to the nearest day if more +#' precision is supplied. Defaults to the day before the current date (i.e., +#' the most recent complete day) if left blank. +#' @param end_date A length-1 vector of class Date, POSIXct, or character in +#' YYYY-MM-DD format. Will be rounded **down** to the nearest day if more +#' precision is supplied. Defaults to the day before the current date (i.e., +#' the most recent complete day) if left blank. +#' @details If neither `start_date` nor `end_date` are supplied, the most recent +#' day of data will be returned. If only `start_date` is supplied, then the +#' end date defaults to the day before the current date (i.e., the most recent +#' complete day). Supplying only `end_date` will result in an error. +#' @note If `station_id` is supplied as a vector, multiple successive calls to +#' the API will be made. You may find better performance getting data for all +#' the stations by leaving `station_id` blank and subsetting the resulting +#' dataframe. Requests for data from all stations for more than 6-12 months +#' may take considerable time. +#' @return A tibble. For units and other metadata, see +#' +#' @seealso [az_15min()], [az_daily()], [az_heat()], [az_hourly()], [az_lw15min()] +#' @source +#' +#' @importFrom rlang .data +#' @export +#' +#' @examples +#' \dontrun{ +#' # Most recent data for all stations: +#' az_lwdaily() +#' +#' # Specify stations: +#' az_lwdaily(station_id = c(1, 2)) +#' az_lwdaily(station_id = c("az01", "az02")) +#' +#' # Specify dates: +#' az_lwdaily(start_date = "2022-09-25") +#' az_lwdaily(start_date = "2022-09-25", end_date = "2022-09-26") +#' } + + +az_lwdaily <- function(station_id = NULL, start_date = NULL, end_date = NULL) { + + # TODO: check for valid station IDs + check_internet() + + if(!is.null(end_date) & is.null(start_date)) { + stop("If you supply `end_date`, you must also supply `start_date`.") + } + + params <- + parse_params( + station_id = station_id, + start = start_date, + end = end_date, + hour = FALSE, + real_time = FALSE + ) + + + # Query API ----------------------------------------------------------------- + + if (is.null(start_date) & is.null(end_date)) { + message("Querying data from ", params$start, " ...") + } else { + message("Querying data from ", params$start, " through ", params$end, " ...") + } + + if (length(station_id) <= 1) { + out <- + retrieve_data( + params$station_id, + params$start_f, + params$time_interval, + endpoint = "lwdaily" + ) + } else if (length(station_id) > 1) { + out <- + purrr::map_df( + params$station_id, + function(x) { + retrieve_data( + x, + params$start_f, + params$time_interval, + endpoint = "lwdaily" + ) + } + ) + } + + if (nrow(out) == 0) { + warning("No data retrieved from API") + # Return 0x0 tibble for type consistency + return(tibble::tibble()) + } + + # Check if any data are missing + n_obs <- out %>% + dplyr::summarise(n = dplyr::n(), .by = dplyr::all_of("meta_station_id")) %>% + dplyr::filter(.data$n < as.numeric(lubridate::period(params$time_interval), "day") + 1) + if (nrow(n_obs) != 0 | + # Also warn if the missing data is just at the end + lubridate::ymd(max(out$date)) < params$end) { + warning("Some requested data were unavailable.") + } + + + # Wrangle output ------------------------------------------------------------- + + out <- out %>% + # Move metadata to beginning + dplyr::select(dplyr::starts_with("meta_"), dplyr::everything()) %>% + dplyr::mutate(dplyr::across( + c(-"meta_station_id", -"meta_station_name", -"date", -"datetime"), + as.numeric + )) %>% + dplyr::filter(.data$meta_station_id != "az99") %>% + dplyr::mutate(date = lubridate::ymd(.data$date)) %>% + dplyr::mutate(datetime = lubridate::ymd_hms(.data$datetime, tz = "America/Phoenix")) %>% + # Convert NAs + dplyr::mutate( + dplyr::across( + tidyselect::where(is.numeric), + function(x) + dplyr::if_else(x %in% c(-999, -9999, -99999, -7999, 999, 999.9, 9999), NA_real_, x) + ) + ) + + if (length(unique(out$date)) == 1) { + message("Returning data from ", unique(out$date)) + } else { + message("Returning data from ", min(out$date), " through ", max(out$date)) + } + return(out) +} diff --git a/R/parse_params.R b/R/parse_params.R index a987fff..9c7f9c3 100644 --- a/R/parse_params.R +++ b/R/parse_params.R @@ -3,14 +3,14 @@ #' @param station_id character or numeric vector #' @param start start date or date time #' @param end end date or date time -#' @param hour logical; do `start` and `end` contain hours? +#' @param hour logical; is request for hourly data? #' @param real_time logical; is request for real-time data? #' #' @note If `hour = TRUE`, `start` and `end` can be character or POSIXct and -#' will be rounded **down** to the nearest hour. If character, then they must +#' will be rounded **down** to the nearest hour. If character, then they must #' at least contain the hour (e.g. "2022-01-12 13" for 1pm on Jan 12, 2022). #' If `hour = FALSE` then class Date is also accepted and values will be -#' rounded **down** to the nearest whole day. Dates and times should be in +#' rounded **down** to the nearest whole day. Dates and times should be in #' Arizona time. #' #' @return a list @@ -59,18 +59,19 @@ parse_params <- function(station_id, start, end, hour = FALSE, real_time = FALSE # start_f/time_interval: what is actually passed to the API ######################################### + if (is.null(end)) { if (isTRUE(hour)) { # Hourly data end_ <- format( # Keep as character until later, for consistency lubridate::floor_date(lubridate::now(tzone = tz), "hour"), "%Y-%m-%d %H:%M:%S" ) - } else if (isTRUE(real_time)) { # 15min data + } else if (isTRUE(real_time)) { # 15min data, both weather and leaf wetness end_ <- format( # Keep as character until later, for consistency lubridate::now(tzone = tz), "%Y-%m-%d %H:%M:%S" ) - } else { # Daily data + } else { # Daily weather and leaf wetness data end_ <- format( # Keep as character until later, for consistency lubridate::today(tzone = tz) - lubridate::days(1), "%Y-%m-%d %H:%M:%S" @@ -80,12 +81,12 @@ parse_params <- function(station_id, start, end, hour = FALSE, real_time = FALSE # For hourly, if only ymd is supplied to `end`, round up to end of day. On a # given day, hourly data go from 1:00:00 to 23:59:59. For 15min, if only ymd # is supplied to `end`, set to current Arizona time. On a given day, 15 min - # data go from 00:00:01 to 23:59:59 + # data go from 00:00:00 to 23:59:59 if (isTRUE(hour) & is_ymd(end)) { # Hourly data end_ <- paste(end, "23:59:59") } else if (isTRUE(real_time) & is_ymd(end)) { # 15min data end_ <- paste(end, format(lubridate::now(tzone = tz), "%H:%M:%S")) - } else { # Daily data + } else { # Daily weather data end_ <- end } } @@ -101,7 +102,7 @@ parse_params <- function(station_id, start, end, hour = FALSE, real_time = FALSE lubridate::now(tzone = tz) - lubridate::minutes(15), "%Y-%m-%d %H:%M:%S" ) - } else { # Daily data + } else { # Daily weather data start_ <- format( # Keep as character until later, for consistency lubridate::today(tzone = tz) - lubridate::days(1), "%Y-%m-%d" @@ -111,8 +112,8 @@ parse_params <- function(station_id, start, end, hour = FALSE, real_time = FALSE if (isTRUE(hour) & is_ymd(start)) { # Hourly data start_ <- paste(start, "01:00:00") } else if (isTRUE(real_time) & is_ymd(start)) { # 15min data - start_ <- paste(start, "00:00:01") - } else { # Daily data + start_ <- paste(start, "00:00:00") + } else { # Daily weather and leaf wetness data start_ <- start } } @@ -135,7 +136,7 @@ parse_params <- function(station_id, start, end, hour = FALSE, real_time = FALSE lubridate::parse_date_time(x, orders = c("YmdHMS", "YmdHM", "YmdH", "Ymd"), tz = tz) %>% lubridate::floor_date(unit = "secs") } - } else { # Daily data + } else { # Daily weather data parse_fun <- function(x, end = FALSE) { lubridate::parse_date_time(x, orders = c("Ymd", "YmdHMS", "YmdHM", "YmdH"), tz = tz) %>% lubridate::floor_date(unit = "day") %>% @@ -193,7 +194,7 @@ parse_params <- function(station_id, start, end, hour = FALSE, real_time = FALSE if (end_parsed < start_parsed) { stop("`end_date_time` is before `start_date_time`!") } - } else { # Daily data + } else { # Daily weather and leaf wetness data if (!is.null(start) & start_parsed >= lubridate::today(tzone = tz)) { stop("Please supply a `start_date` earlier than today.") } @@ -219,13 +220,27 @@ parse_params <- function(station_id, start, end, hour = FALSE, real_time = FALSE # as one full hour. if (is.null(start)) { time_interval <- "*" - } else { + } else if (real_time == FALSE) { end_rounded <- lubridate::round_date(end_parsed, unit = "hour") start_rounded <- lubridate::round_date(start_parsed, unit = "hour") d <- lubridate::as.period(end_rounded - start_rounded) time_interval <- lubridate::format_ISO8601(d) + } else { # real_time == TRUE + end_rounded <- lubridate::round_date(end_parsed, unit = "minute") + start_rounded <- lubridate::round_date(start_parsed, unit = "minute") + d <- lubridate::as.period(end_parsed - start_parsed) + time_interval <- lubridate::format_ISO8601(d) } + #if (is.null(start)) { + # time_interval <- "*" + #} else { + # end_rounded <- lubridate::round_date(end_parsed, unit = "hour") + # start_rounded <- lubridate::round_date(start_parsed, unit = "hour") + # d <- lubridate::as.period(end_rounded - start_rounded) + # time_interval <- lubridate::format_ISO8601(d) + #} + # Return list # URLencode isn't strictly necessary, but it'll make the correct error print diff --git a/R/retrieve_data.R b/R/retrieve_data.R index 1477f6e..a166298 100644 --- a/R/retrieve_data.R +++ b/R/retrieve_data.R @@ -3,7 +3,7 @@ #' @param station_id character; in the format of "az01" #' @param start_f character; ISO formatted date time string #' @param time_interval character; ISO8601 formatted time interval string -#' @param endpoint character; one of "daily", "hourly", "hueto", or "fifteen" +#' @param endpoint character; one of "15min", "daily", "hourly", "hueto", "lw15min", or "lwdaily" #' @param print_call logical; when TRUE, prints the HTTP request to the AZMet API #' #' @return tibble @@ -15,7 +15,7 @@ retrieve_data <- station_id, start_f, time_interval, - endpoint = c("15min", "daily", "hourly", "hueto", "lw15min"), + endpoint = c("15min", "daily", "hourly", "hueto", "lw15min", "lwdaily"), print_call = getOption("azmet.print_api_call") ) { @@ -43,9 +43,9 @@ retrieve_data <- data_tidy <- data_raw$data %>% purrr::compact() %>% - purrr::map(purrr::compact) %>% #removes any columns that are NULL (i.e. no data) + purrr::map(purrr::compact) %>% # Removes any columns that are NULL (i.e. no data) purrr::map(tibble::as_tibble) %>% - purrr::list_rbind() # missing columns for individual sites will be all NAs + purrr::list_rbind() # Missing columns for individual sites will be all NAs attributes(data_tidy) <- append( @@ -54,5 +54,5 @@ retrieve_data <- ) data_tidy - #TODO: Check for 0x0 tibble and error + # TODO: Check for 0x0 tibble and error } diff --git a/man/az_15min.Rd b/man/az_15min.Rd index 7b0d9ad..d7182a2 100644 --- a/man/az_15min.Rd +++ b/man/az_15min.Rd @@ -26,16 +26,17 @@ Defaults to the current date and time if left blank and \code{start_date_time} is specified.} } \value{ -a tibble. For units and other metadata, see +A tibble. For units and other metadata, see \url{https://azmet.arizona.edu/about} } \description{ Retrieves 15-minute data from the AZMet (Arizona Meteorological Network) API. -For a list of weather stations and their locations see \link{station_info}. +For a list of weather stations and their locations see \link{station_info}, or +visit https://azmet.arizona.edu/about. } \details{ If neither \code{start_date_time} nor \code{end_date_time} are supplied, the -most recent date-time of data will be returned. If only \code{start_date_time} +most recent datetime of data will be returned. If only \code{start_date_time} is supplied, then \code{end_date_time} defaults to the current time. Supplying only \code{end_date_time} will result in an error. } @@ -61,5 +62,5 @@ az_15min(start_date_time = "2022-09-25 01:00:00", end_date_time = "2022-09-25 07 } } \seealso{ -\code{\link[=az_daily]{az_daily()}}, \code{\link[=az_heat]{az_heat()}}, \code{\link[=az_hourly]{az_hourly()}}, \code{\link[=az_lw15min]{az_lw15min()}} +\code{\link[=az_daily]{az_daily()}}, \code{\link[=az_heat]{az_heat()}}, \code{\link[=az_hourly]{az_hourly()}}, \code{\link[=az_lw15min]{az_lw15min()}}, \code{\link[=az_lwdaily]{az_lwdaily()}} } diff --git a/man/az_add_units.Rd b/man/az_add_units.Rd index 8bd8291..81435c4 100644 --- a/man/az_add_units.Rd +++ b/man/az_add_units.Rd @@ -7,10 +7,10 @@ az_add_units(x) } \arguments{ -\item{x}{a tibble output by \code{\link[=az_hourly]{az_hourly()}}, \code{\link[=az_daily]{az_daily()}}, or \code{\link[=az_heat]{az_heat()}}} +\item{x}{A tibble output by \code{\link[=az_hourly]{az_hourly()}}, \code{\link[=az_daily]{az_daily()}}, or \code{\link[=az_heat]{az_heat()}}} } \value{ -a tibble with columns of class "units" +A tibble with columns of class "units" } \description{ Assigns correct units to the output of \code{az_hourly()}, \code{az_daily()}, and diff --git a/man/az_daily.Rd b/man/az_daily.Rd index 94ddc5c..036ed70 100644 --- a/man/az_daily.Rd +++ b/man/az_daily.Rd @@ -4,37 +4,41 @@ \alias{az_daily} \title{Retrieve Daily Weather Data from AZMET} \source{ -\url{https://ag.arizona.edu/azmet/} +\url{https://azmet.arizona.edu/} } \usage{ az_daily(station_id = NULL, start_date = NULL, end_date = NULL) } \arguments{ \item{station_id}{station ID can be supplied as numeric vector (e.g. -\code{station_id = c(8, 37)}) or as character vector with the prefix "az" and 2 -digits (e.g. \code{station_id = c("az08", "az37")}) If left blank data for all -stations will be returned} +\code{station_id = c(8, 37)}) or as character vector with the prefix "az" and +two digits (e.g. \code{station_id = c("az08", "az37")}). If left blank, data for all +stations will be returned.} \item{start_date}{A length-1 vector of class Date, POSIXct, or character in -YYYY-MM-DD format. Will be rounded \strong{down} to the nearest day if more -precision is supplied.} +YYYY-MM-DD format. Will be rounded \strong{down} to the nearest day if more +precision is supplied. Defaults to the day before the current date (i.e., +the most recent complete day) if left blank.} \item{end_date}{A length-1 vector of class Date, POSIXct, or character in -YYYY-MM-DD format. Will be rounded \strong{down} to the nearest day if more -precision is supplied. Defaults to the current date if left blank.} +YYYY-MM-DD format. Will be rounded \strong{down} to the nearest day if more +precision is supplied. Defaults to the day before the current date (i.e., +the most recent complete day) if left blank.} } \value{ -a tibble. For units and other metadata, see -\url{https://ag.arizona.edu/azmet/raw2003.htm} +A tibble. For units and other metadata, see +\url{https://azmet.arizona.edu/about} } \description{ Retrieves daily data from the Arizona Meteorological Network API. For a list -of weather stations and their locations see \link{station_info}. +of weather stations and their locations see \link{station_info}, or visit +https://azmet.arizona.edu/about. } \details{ If neither \code{start_date} nor \code{end_date} are supplied, the most recent -day of data will be returned. If only \code{start_date} is supplied, then the -end date defaults to the current date. Supplying only \code{end_date} will +day of data will be returned. If only \code{start_date} is supplied, then the +end date defaults to the day before the current date (i.e., +the most recent complete day). Supplying only \code{end_date} will result in an error. } \note{ @@ -57,8 +61,7 @@ az_daily(station_id = c("az01", "az02")) az_daily(start_date = "2022-09-25") az_daily(start_date = "2022-09-25", end_date = "2022-09-26") } - } \seealso{ -\code{\link[=az_15min]{az_15min()}}, \code{\link[=az_heat]{az_heat()}}, \code{\link[=az_hourly]{az_hourly()}}, \code{\link[=az_lw15min]{az_lw15min()}} +\code{\link[=az_15min]{az_15min()}}, \code{\link[=az_heat]{az_heat()}}, \code{\link[=az_hourly]{az_hourly()}}, \code{\link[=az_lw15min]{az_lw15min()}}, \code{\link[=az_lwdaily]{az_lwdaily()}} } diff --git a/man/az_heat.Rd b/man/az_heat.Rd index effa42c..6d02d8c 100644 --- a/man/az_heat.Rd +++ b/man/az_heat.Rd @@ -4,7 +4,7 @@ \alias{az_heat} \title{Retrieve Accumulated Heat Units and Evapotranspiration} \source{ -\url{https://ag.arizona.edu/azmet/} +\url{https://azmet.arizona.edu/} } \usage{ az_heat(station_id = NULL, start_date = NULL, end_date = NULL) @@ -26,14 +26,15 @@ an \code{end_date} is supplied, then data will be cumulative from the start of the year of \code{end_date}.} } \value{ -a tibble. For units and other metadata, see -\url{https://ag.arizona.edu/azmet/raw2003.htm} +A tibble. For units and other metadata, see +\url{https://azmet.arizona.edu/about} } \description{ Retrieves accumulated heat units and reference evapotranspiration units from -the Arizona Meteorological Network API. By default, returned values are +the Arizona Meteorological Network API. By default, returned values are cumulative since January 1 of the current year. For a list of weather -stations and their locations see \link{station_info}. +stations and their locations see \link{station_info}, or visit +https://azmet.arizona.edu/about. } \details{ Unlike \code{\link[=az_daily]{az_daily()}}, only one row of data per station is returned, @@ -67,5 +68,5 @@ az_heat(end_date = paste(yr, "03", "31", sep = "-")) } \seealso{ -\code{\link[=az_15min]{az_15min()}}, \code{\link[=az_daily]{az_daily()}}, \code{\link[=az_hourly]{az_hourly()}}, \code{\link[=az_lw15min]{az_lw15min()}} +\code{\link[=az_15min]{az_15min()}}, \code{\link[=az_daily]{az_daily()}}, \code{\link[=az_hourly]{az_hourly()}}, \code{\link[=az_lw15min]{az_lw15min()}}, \code{\link[=az_lwdaily]{az_lwdaily()}} } diff --git a/man/az_hourly.Rd b/man/az_hourly.Rd index 9519ea6..72e70f7 100644 --- a/man/az_hourly.Rd +++ b/man/az_hourly.Rd @@ -4,7 +4,7 @@ \alias{az_hourly} \title{Retrieve Hourly Weather Data} \source{ -\url{https://ag.arizona.edu/azmet/} +\url{https://azmet.arizona.edu/} } \usage{ az_hourly(station_id = NULL, start_date_time = NULL, end_date_time = NULL) @@ -12,7 +12,7 @@ az_hourly(station_id = NULL, start_date_time = NULL, end_date_time = NULL) \arguments{ \item{station_id}{station ID can be supplied as numeric vector (e.g. \code{station_id = c(8, 37)}) or as character vector with the prefix "az" and 2 -digits (e.g. \code{station_id = c("az08", "az37")}) If left blank data for all +digits (e.g. \code{station_id = c("az08", "az37")}) If left blank, data for all stations will be returned} \item{start_date_time}{A length-1 vector of class POSIXct or character in @@ -28,12 +28,13 @@ Defaults to the current date and time if left blank and \code{start_date_time} is specified.} } \value{ -a tibble. For units and other metadata, see -\url{https://ag.arizona.edu/azmet/raw2003.htm} +A tibble. For units and other metadata, see +\url{https://azmet.arizona.edu/about} } \description{ Retrieves hourly weather data from the Arizona Meteorological Network API. -For a list of weather stations and their locations see \link{station_info}. +For a list of weather stations and their locations see \link{station_info}, or +visit https://azmet.arizona.edu/about. } \details{ If neither \code{start_date_time} nor \code{end_date_time} are supplied, the @@ -64,5 +65,5 @@ az_hourly(start_date_time = "2022-09-25 01", end_date = "2022-09-25 20") } \seealso{ -\code{\link[=az_15min]{az_15min()}}, \code{\link[=az_daily]{az_daily()}}, \code{\link[=az_heat]{az_heat()}}, \code{\link[=az_lw15min]{az_lw15min()}} +\code{\link[=az_15min]{az_15min()}}, \code{\link[=az_daily]{az_daily()}}, \code{\link[=az_heat]{az_heat()}}, \code{\link[=az_lw15min]{az_lw15min()}}, \code{\link[=az_lwdaily]{az_lwdaily()}} } diff --git a/man/az_lw15min.Rd b/man/az_lw15min.Rd index 4d4befe..3933e8b 100644 --- a/man/az_lw15min.Rd +++ b/man/az_lw15min.Rd @@ -26,17 +26,18 @@ Defaults to the current date and time if left blank and \code{start_date_time} is specified.} } \value{ -a tibble. For units and other metadata, see +A tibble. For units and other metadata, see \url{https://azmet.arizona.edu/about} } \description{ Retrieves 15-minute leaf-wetness data from the AZMet (Arizona Meteorological -Network) API. Currently, these data only are available from stations in the -Yuma area. For a list of stations and their locations see \link{station_info}. +Network) API. Currently, these data only are available from weather stations +in the Yuma area. For a list of stations and their locations see +\link{station_info}, or visit https://azmet.arizona.edu/about. } \details{ If neither \code{start_date_time} nor \code{end_date_time} are supplied, the -most recent date-time of data will be returned. If only \code{start_date_time} +most recent datetime of data will be returned. If only \code{start_date_time} is supplied, then \code{end_date_time} defaults to the current time. Supplying only \code{end_date_time} will result in an error. } @@ -62,5 +63,5 @@ az_lw15min(start_date_time = "2022-09-25 01:00:00", end_date_time = "2022-09-25 } } \seealso{ -\code{\link[=az_15min]{az_15min()}}, \code{\link[=az_daily]{az_daily()}}, \code{\link[=az_heat]{az_heat()}}, \code{\link[=az_hourly]{az_hourly()}} +\code{\link[=az_15min]{az_15min()}}, \code{\link[=az_daily]{az_daily()}}, \code{\link[=az_heat]{az_heat()}}, \code{\link[=az_hourly]{az_hourly()}}, \code{\link[=az_lwdaily]{az_lwdaily()}} } diff --git a/man/az_lwdaily.Rd b/man/az_lwdaily.Rd new file mode 100644 index 0000000..be7f58c --- /dev/null +++ b/man/az_lwdaily.Rd @@ -0,0 +1,67 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/az_lwdaily.R +\name{az_lwdaily} +\alias{az_lwdaily} +\title{Retrieve Daily Leaf Wetness Data from AZMet} +\source{ +\url{https://azmet.arizona.edu/} +} +\usage{ +az_lwdaily(station_id = NULL, start_date = NULL, end_date = NULL) +} +\arguments{ +\item{station_id}{station ID can be supplied as numeric vector (e.g. +\code{station_id = c(8, 37)}) or as character vector with the prefix "az" and +two digits (e.g. \code{station_id = c("az08", "az37")}). If left blank, data for +all stations will be returned.} + +\item{start_date}{A length-1 vector of class Date, POSIXct, or character in +YYYY-MM-DD format. Will be rounded \strong{down} to the nearest day if more +precision is supplied. Defaults to the day before the current date (i.e., +the most recent complete day) if left blank.} + +\item{end_date}{A length-1 vector of class Date, POSIXct, or character in +YYYY-MM-DD format. Will be rounded \strong{down} to the nearest day if more +precision is supplied. Defaults to the day before the current date (i.e., +the most recent complete day) if left blank.} +} +\value{ +A tibble. For units and other metadata, see +\url{https://azmet.arizona.edu/about} +} +\description{ +Retrieves daily leaf wetness data from the Arizona Meteorological Network +API. Currently, these data only are available from weather stations in the +Yuma area. For a list of stations and their locations see \link{station_info}, or +visit https://azmet.arizona.edu/about. +} +\details{ +If neither \code{start_date} nor \code{end_date} are supplied, the most recent +day of data will be returned. If only \code{start_date} is supplied, then the +end date defaults to the day before the current date (i.e., the most recent +complete day). Supplying only \code{end_date} will result in an error. +} +\note{ +If \code{station_id} is supplied as a vector, multiple successive calls to +the API will be made. You may find better performance getting data for all +the stations by leaving \code{station_id} blank and subsetting the resulting +dataframe. Requests for data from all stations for more than 6-12 months +may take considerable time. +} +\examples{ +\dontrun{ +# Most recent data for all stations: +az_lwdaily() + +# Specify stations: +az_lwdaily(station_id = c(1, 2)) +az_lwdaily(station_id = c("az01", "az02")) + +# Specify dates: +az_lwdaily(start_date = "2022-09-25") +az_lwdaily(start_date = "2022-09-25", end_date = "2022-09-26") +} +} +\seealso{ +\code{\link[=az_15min]{az_15min()}}, \code{\link[=az_daily]{az_daily()}}, \code{\link[=az_heat]{az_heat()}}, \code{\link[=az_hourly]{az_hourly()}}, \code{\link[=az_lw15min]{az_lw15min()}} +} diff --git a/tests/testthat/test-az_15min.R b/tests/testthat/test-az_15min.R new file mode 100644 index 0000000..d52f9d5 --- /dev/null +++ b/tests/testthat/test-az_15min.R @@ -0,0 +1,101 @@ +library(lubridate) +skip_if_offline() +skip_if_not(ping_service()) +skip_on_cran() + +test_that("start_date_time works as expected", { + res <- suppressWarnings( + az_15min( + station_id = 1, + start_date_time = paste0(lubridate::today(tzone = "America/Phoenix"), " 02"), + end_date_time = paste0(lubridate::today(tzone = "America/Phoenix"), " 03") + ) + ) + expect_equal(nrow(res), 4) +}) + +test_that("works with station_id as a vector", { + res <- + suppressWarnings( + az_15min( + station_id = c(1, 2), + start_date_time = paste0(lubridate::today(tzone = "America/Phoenix"), " 02"), + end_date_time = paste0(lubridate::today(tzone = "America/Phoenix"), " 03") + ) + ) + expect_s3_class(res, "data.frame") + expect_equal(unique(res$meta_station_id), c("az01", "az02")) +}) + +test_that("data is in correct format", { + res_default <- + suppressWarnings( + az_15min( + start_date_time = paste0(lubridate::today(tzone = "America/Phoenix"), " 02"), + end_date_time = paste0(lubridate::today(tzone = "America/Phoenix"), " 03") + ) + ) + expect_type(res_default$meta_station_name, "character") + expect_type(res_default$precip_total_mm, "double") + expect_s3_class(res_default$datetime, "POSIXct") +}) + +test_that("no data is returned as 0x0 tibble", { + skip("not sure how to reproduce this now that request for historical data error") + res_nodata <- + suppressWarnings( + az_15min(start_date_time = "1980-01-01 00", end_date_time = "1980-01-02 00") + ) + expect_true(nrow(res_nodata) == 0) + expect_s3_class(res_nodata, "tbl_df") +}) + +test_that("requests with 23:59:59 work", { + h <- + suppressWarnings( + az_15min( + station_id = "az01", + start_date_time = paste0(lubridate::today(tzone = "America/Phoenix") - 1, " 23:00"), + end_date_time = paste0(lubridate::today(tzone = "America/Phoenix") - 1, " 23:59") + ) + ) + expect_equal(nrow(h), 4) +}) + +test_that("start=NULL, end=NULL works as expected", { + expect_message({ + null_null <- + suppressWarnings( + az_15min( + station_id = "az01" + ) + ) + }, glue::glue("Querying most recent datetime of 15-minute data ...")) + expect_equal(nrow(null_null), 1) +}) + +test_that("end=NULL works as expected", { + dt_start <- lubridate::now(tzone = "America/Phoenix") - lubridate::minutes(15) + end_null <- + suppressWarnings( + az_15min( + station_id = "az02", + start_date_time = dt_start + ) + ) + expect_equal(nrow(end_null), 1) +}) + +test_that("start as date only is rounded correctly", { + start_input <- lubridate::ymd(lubridate::today(tzone = "America/Phoenix")) + end_hour <- paste0(lubridate::today(tzone = "America/Phoenix"), " 01:00:00") + start_ymd <- + suppressWarnings( + az_15min( + station_id = "az01", + start_date_time = start_input, + end_date_time = end_hour + ) + ) + expect_equal(nrow(start_ymd), 4) +}) diff --git a/tests/testthat/test-az_hourly.R b/tests/testthat/test-az_hourly.R index 6cd7544..57a0ab5 100644 --- a/tests/testthat/test-az_hourly.R +++ b/tests/testthat/test-az_hourly.R @@ -58,7 +58,7 @@ test_that("start=NULL, end=NULL works as expected", { az_hourly( station_id = "az01" ) - }, glue::glue("Querying most recent hour of data")) + }, glue::glue("Querying most recent hour of data ...")) expect_equal(nrow(null_null), 1) #could be that current hour hasn't hit API yet. @@ -101,4 +101,3 @@ test_that("start as date only is rounded correctly", { ) expect_equal(min(date_null$date_datetime), start_actual) }) - diff --git a/tests/testthat/test-az_lw15min.R b/tests/testthat/test-az_lw15min.R new file mode 100644 index 0000000..8c97b7c --- /dev/null +++ b/tests/testthat/test-az_lw15min.R @@ -0,0 +1,101 @@ +library(lubridate) +skip_if_offline() +skip_if_not(ping_service()) +skip_on_cran() + +test_that("start_date_time works as expected", { + res <- suppressWarnings( + az_lw15min( + station_id = 1, + start_date_time = paste0(lubridate::today(tzone = "America/Phoenix"), " 02"), + end_date_time = paste0(lubridate::today(tzone = "America/Phoenix"), " 03") + ) + ) + expect_equal(nrow(res), 5) +}) + +test_that("works with station_id as a vector", { + res <- + suppressWarnings( + az_lw15min( + station_id = c(1, 2), + start_date_time = paste0(lubridate::today(tzone = "America/Phoenix"), " 02"), + end_date_time = paste0(lubridate::today(tzone = "America/Phoenix"), " 03") + ) + ) + expect_s3_class(res, "data.frame") + expect_equal(unique(res$meta_station_id), c("az01", "az02")) +}) + +test_that("data is in correct format", { + res_default <- + suppressWarnings( + az_lw15min( + start_date_time = paste0(lubridate::today(tzone = "America/Phoenix"), " 02"), + end_date_time = paste0(lubridate::today(tzone = "America/Phoenix"), " 03") + ) + ) + expect_type(res_default$meta_station_name, "character") + expect_type(res_default$temp_wetbulb_meanC, "double") + expect_s3_class(res_default$datetime, "POSIXct") +}) + +test_that("no data is returned as 0x0 tibble", { + skip("not sure how to reproduce this now that request for historical data error") + res_nodata <- + suppressWarnings( + az_lw15min(start_date_time = "1980-01-01 00", end_date_time = "1980-01-02 00") + ) + expect_true(nrow(res_nodata) == 0) + expect_s3_class(res_nodata, "tbl_df") +}) + +test_that("requests with 23:59:59 work", { + h <- + suppressWarnings( + az_lw15min( + station_id = "az02", + start_date_time = paste0(lubridate::today(tzone = "America/Phoenix") - 1, " 23:00"), + end_date_time = paste0(lubridate::today(tzone = "America/Phoenix") - 1, " 23:59") + ) + ) + expect_equal(nrow(h), 4) +}) + +test_that("start=NULL, end=NULL works as expected", { + expect_message({ + null_null <- + suppressWarnings( + az_lw15min( + station_id = "az02" + ) + ) + }, glue::glue("Querying most recent datetime of leaf wetness 15-minute data ...")) + expect_equal(nrow(null_null), 1) +}) + +test_that("end=NULL works as expected", { + dt_start <- lubridate::now(tzone = "America/Phoenix") - lubridate::minutes(15) + end_null <- + suppressWarnings( + az_lw15min( + station_id = "az02", + start_date_time = dt_start + ) + ) + expect_equal(nrow(end_null), 1) +}) + +test_that("start as date only is rounded correctly", { + start_input <- lubridate::ymd(lubridate::today(tzone = "America/Phoenix")) + end_hour <- paste0(lubridate::today(tzone = "America/Phoenix"), " 01:00:00") + start_ymd <- + suppressWarnings( + az_lw15min( + station_id = "az02", + start_date_time = start_input, + end_date_time = end_hour + ) + ) + expect_equal(nrow(start_ymd), 4) +}) diff --git a/tests/testthat/test-az_lwdaily.R b/tests/testthat/test-az_lwdaily.R new file mode 100644 index 0000000..f069b89 --- /dev/null +++ b/tests/testthat/test-az_lwdaily.R @@ -0,0 +1,79 @@ +skip_if_offline() +skip_if_not(ping_service()) +skip_on_cran() + +test_that("numeric station_ids work", { + res_station <- az_lwdaily(station_id = 9) + expect_s3_class(res_station, "data.frame") +}) + +test_that("start_date works as expected", { + start <- "2024-07-01" + end <- "2024-07-07" + expect_message( + res_start <- az_lwdaily(station_id = 1, start_date = start, end_date = end), + "Querying data from 2024-07-01 through 2024-07-07" + ) + expect_equal(nrow(res_start), 7) +}) + +test_that("works with station_id as a vector", { + res_2 <- az_lwdaily(station_id = c(1, 2)) + expect_equal(unique(res_2$meta_station_id), c("az01", "az02")) + expect_s3_class(res_2, "data.frame") +}) + +test_that("data is in correct format", { + res_default <- az_lwdaily() + expect_type(res_default$meta_station_name, "character") + expect_type(res_default$dwpt_30cm_mean, "double") + expect_s3_class(res_default$date, "Date") +}) + +test_that("NAs converted correctly", { + res_missing <- az_lwdaily(station_id = 1, start_date = "2024-07-01", end_date = "2024-07-01") + expect_true(is.na(res_missing$dwpt_30cm_mean)) + expect_true(is.na(res_missing$lw1_total_wet_mins)) + expect_true(is.na(res_missing$relative_humidity_30cm_min)) + expect_true(is.na(res_missing$temp_air_30cm_maxC)) +}) + +test_that("no data is returned as 0x0 tibble", { + skip("Not sure how to reproduce this anymore now that these dates error") + res_nodata <- + suppressWarnings( + az_lwdaily(start_date = "1980-01-01", end_date = "1980-01-02") + ) + expect_true(nrow(res_nodata) == 0) + expect_s3_class(res_nodata, "tbl_df") +}) + +test_that("warn when some data missing", { + expect_warning( + az_lwdaily(station_id = "az32", start_date = "2023-07-01", end_date = "2024-07-01") + ) +}) + +test_that("start=NULL, end=NULL works correctly", { + null_null <- az_lwdaily(station_id = 2) + expect_equal(nrow(null_null), 1) +}) + +test_that("end=NULL works correctly", { + date_start <- lubridate::today(tzone = "America/Phoenix") - 2 + last_date <- date_start + 1 + expect_message( + date_null <- az_lwdaily(station_id = "az01", start_date = date_start), + glue::glue("Querying data from {date_start} through {last_date} ...") + ) + expect_message( + date_null <- az_lwdaily(station_id = "az01", start_date = date_start), + glue::glue("Returning data from {date_start}") + ) + expect_equal(date_null$date, seq(date_start, last_date, by = "day")) +}) + +test_that("start=NULL works correctly", { + last_date <- lubridate::today(tzone = "America/Phoenix") - 1 + expect_error(az_lwdaily(end = last_date), "If you supply `end_date`, you must also supply `start_date`") +})