#' Validate FB Sentry API key
#'
#' Tests the connection to the FB Sentry API
#'
#' @rdname fb_validate_key
#' @author Bill DeVoe, \email{William.DeVoe@@maine.gov}
#' @param url **String** - URL to the FB Sentry API; defaults to version 2 URL.
#' @param key **String** - Name of the Windows environment variable containing
#' the API key.
#' @param stop **Boolean** - If false, the function will return a false value if
#' the connection fails; if true (the default), the function will stop.
#' @return Boolean; true if connection was successful.
#' @export
#' @import httr
#' @import jsonlite
fb_validate_key <- function(url = "https://fb-sentrygps.com/api/v2/",
key, stop = T) {
key_str <- Sys.getenv(key)
if (key_str == '') {stop("Invalid environment variable for API key.")}
body <- list(commandstring = "validate_api_key", token = key_str)
req <- httr::POST(url, body = body, encode = "json")
httr::stop_for_status(req)
json <- httr::content(req, "text")
response <- jsonlite::fromJSON(json)
if (response$message == "Valid API key.") {
result = TRUE
message("Connection to API succeeded.")
} else {
result = FALSE
if (stop == T) {
stop(paste0("Connection to API failed - ", response$message))
}
warning(paste0("Connection to API failed - ", response$message))
}
return(result)
}
#' List FB Sentry devices
#'
#' Lists devices for a given FB Sentry API key.
#'
#' @rdname fb_list_devices
#' @author Bill DeVoe, \email{William.DeVoe@@maine.gov}
#' @param url **String** - URL to the FB Sentry API. Defaults to version 2 URL.
#' @param key **String** - Name of the Windows environment variable containing
#' the API key.
#' @return **Dataframe** - Dataframe listing devices.
#' @export
fb_list_devices <- function(url = "https://fb-sentrygps.com/api/v2/", key) {
key_str <- Sys.getenv(key)
if (key_str == '') {stop("Invalid environment variable for API key.")}
# Test API connection
test <- fb_validate_key(url, key)
body <- list(commandstring = "get_devices", token = key_str)
req <- httr::POST(url, body = body, encode = "json")
httr::stop_for_status(req)
json <- httr::content(req, "text")
response <- jsonlite::fromJSON(json)
return(response$data)
}
#' All FB Sentry data for all devices for date range
#'
#' Pulls all data from FB Sentry API profile for a given date range.
#'
#' @rdname fb_all_data
#' @author Bill DeVoe, \email{William.DeVoe@@maine.gov}
#' @param url **String** - URL to the FB Sentry API; defaults to version 2 URL.
#' @param key **String** - Name of the Windows environment variable containing
#' the API key.
#' @param timebegin **String** - Retrieve reports after this datetime (UTC).
#' Format: MM/dd/yyyy HH:mm:ss
#' @param timeend **String** - Retrieve reports before this datetime (UTC).
#' Format: MM/dd/yyyy HH:mm:ss
#' @param local **Boolean** - Convert timestamps to local timezone. Default True
#' @param short **Boolean** *Optional* - Indicate whether to return short or
#' long version of report; defaults to true (short).
#' @param devices **Character Vector** *Optional* - deviceIDs to include in the
#' returned data.
#' @return SpatialPoints Dataframe of tracking data.
#' @export
#' @import sp
#' @importFrom methods hasArg
fb_all_data <- function(url = "https://fb-sentrygps.com/api/v2/",
key, timebegin, timeend, local = T, short= T, devices) {
# Check date args
fb_validate_date(timebegin)
fb_validate_date(timeend)
key_str <- Sys.getenv(key)
if (key_str == '') {stop("Invalid environment variable for API key.")}
# Set proj4strings variables for WGS84 decimal degrees
WGS84 = "+init=epsg:4326"
# Test API connection
test <- fb_validate_key(url, key)
message("Downloading data from API...")
# Define JSON payload
body <- list(commandstring = "get_reports_all_devices",
datetime_start = timebegin, datetime_end = timeend,
coredataonly = short, token = key_str)
# Execute POST JSON request
req <- httr::POST(url, body = body, encode = "json")
httr::stop_for_status(req)
json <- httr::content(req, "text")
rm(req)
# Parse JSON
response <- jsonlite::fromJSON(json)
rm(json)
# Check for errors
if (length(response$isError) > 0) {
if (response$isError) {
stop(response$msg)
}
}
data <- response$data
rm(response)
# Filter data by device ID vector if it has been provided.
if (hasArg(devices)) {
message("Filtering by deviceId...")
data <- data[data$deviceId %in% devices,]
}
# Parse datetime fields into datetime type
data[['receivedDate']] <- strptime(data[['receivedDate']],
format='%m/%d/%Y %H:%M:%S')
data[['updateTime']] <- strptime(data[['updateTime']],
format='%m/%d/%Y %H:%M:%S')
data$receivedDate <- as.POSIXct(data$receivedDate, tz="UTC")
data$updateTime <- as.POSIXct(data$updateTime, tz="UTC")
# Convert to local time
if (local == T) {
attributes(data$receivedDate)$tzone <- Sys.timezone()
attributes(data$updateTime)$tzone <- Sys.timezone()
}
# Remove null lat/lons and values outside lat/lon range
data <- data[data$latitude != 0,]
data <- data[data$longitude != 0,]
data <- data[data$longitude <= 180,]
data <- data[data$longitude >= -180,]
data <- data[data$latitude <= 90,]
data <- data[data$latitude >= -90,]
# Build spatial dataframe out of data table
sp::coordinates(data) = ~longitude+latitude
#add WGS84 projection to spatial dataframe
sp::proj4string(data) = sp::CRS(WGS84)
# Order data by deviceID and then updatetime (order of track lines)
data <- data[order(data$deviceId, data$updateTime), ]
return(data)
}
#' All FB Sentry data for device(s) for a given date range
#'
#' Pulls all data from FB Sentry API profile for a given vector of deviceIDs.
#'
#' @rdname fb_device_data
#' @author Bill DeVoe, \email{William.DeVoe@@maine.gov}
#' @param url **String** - URL to the FB Sentry API; defaults to version 2 URL.
#' @param key **String** - Name of the Windows environment variable containing
#' the API key.
#' @param timebegin **String** - Retrieve reports after this datetime (UTC).
#' Format: MM/dd/yyyy HH:mm:ss
#' @param timeend **String** - Retrieve reports before this datetime (UTC).
#' Format: MM/dd/yyyy HH:mm:ss
#' @param local **Boolean** - Convert timestamps to local timezone.
#' @param short **Boolean** - Indicate whether to return short or long version
#' of report; defaults to true (short).
#' @param devices **Character Vector** - deviceIDs to include in the returned
#' data.
#' @return SpatialPoints Dataframe of tracking data.
#' @export
fb_device_data <- function(url = "https://fb-sentrygps.com/api/v2/", key, timebegin, timeend,
local = T, short=T, devices) {
# Check date args
fb_validate_date(timebegin)
fb_validate_date(timeend)
key_str <- Sys.getenv(key)
if (key_str == '') {stop("Invalid environment variable for API key.")}
# Set proj4strings variables for WGS84 decimal degrees
WGS84 = "+init=epsg:4326"
# Test API connection
test <- fb_validate_key(url, key)
for (device in devices) {
# Define JSON payload
body <- list(commandstring = "get_reports_single_device",
identifier = device, datetime_start = timebegin,
datetime_end = timeend, coredataonly = short, token = key_str)
# Execute POST JSON request
req <- httr::POST(url, body = body, encode = "json")
httr::stop_for_status(req)
json <- httr::content(req, "text")
# Parse JSON
response <- jsonlite::fromJSON(json)
rm(json)
# Check for errors
if (length(response$isError) > 0) {
if (response$isError) {
next(paste0(device, " failed. ", response$msg))
}
}
device_data <- response$data
# If the first device
if (device == devices[1]) {
data <- device_data
}
else {data <- rbind(data, device_data)}
rm(device_data)
}
# Parse datetime fields into datetime type
data[['receivedDate']] <- strptime(data[['receivedDate']],
format='%m/%d/%Y %H:%M:%S')
data[['updateTime']] <- strptime(data[['updateTime']],
format='%m/%d/%Y %H:%M:%S')
data$receivedDate <- as.POSIXct(data$receivedDate, tz="UTC")
data$updateTime <- as.POSIXct(data$updateTime, tz="UTC")
# Convert to local time
if (local == T) {
attributes(data$receivedDate)$tzone <- Sys.timezone()
attributes(data$updateTime)$tzone <- Sys.timezone()
}
# Remove null lat/lons and weird values
data <- data[data$latitude != 0,]
data <- data[data$longitude != 0,]
data <- data[data$longitude <= 180,]
data <- data[data$longitude >= -180,]
data <- data[data$latitude <= 90,]
data <- data[data$latitude >= -90,]
# Build spatial dataframe out of data table
sp::coordinates(data) = ~longitude+latitude
# Add WGS84 projection to spatial dataframe
sp::proj4string(data) = sp::CRS(WGS84)
# Order data by deviceID and then updatetime (order of track lines)
data <- data[order(data$deviceId, data$updateTime), ]
return(data)
}
#' Validate FB Sentry date string
#'
#' Checks that a provided date string is properly formated
#' for the API call.
#'
#' @rdname fb_validate_date
#' @author Bill DeVoe, \email{William.DeVoe@@maine.gov}
#' @param date **String** - Datetime argument
#' @return Boolean; true if properly formatted. An error is thrown
#' if the data is improperly formatted.
fb_validate_date <- function(date) {
dt <- strptime(x = date, tz = Sys.timezone(), format = "%m/%d/%Y %H:%M:%S")
if (!(is.na(dt))) {return(T)}
else {stop(paste0(date," is not properly formatted as MM/dd/yyyy HH:mm:ss"))}
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.