Degree Days

Degree Days

Weather Data for Energy Saving

Access the Degree Days.net API using R

This page has some sample code showing how to use R to specify a JSON request, send it to our API servers (past the security system), and process the JSON response that comes back.

It's not a full client library (like we have for Java, .NET, and Python), but it should be pretty easy to adapt it to suit your needs.

See the JSON API docs for more about specifying the data you want in the JSON request. There are lots of options, and the request included in the R code below is just a simple example. The JSON docs also explain more about the data you can expect back in the response.

You might also find the JSON API test tool useful for testing different JSON requests and seeing the JSON responses that come back.

# We need to import 5 packages.  You will need to install these in R first.
# See www.degreedays.net/api/r#packages for installation instructions.
library(httr) # for HTTP requests
library(jsonlite) # for dealing with JSON objects
library(digest) # for generating HMAC signatures (for the security scheme)
library(uuid) # for generating random strings (for the security scheme)
library(chron) # for dealing with date-times

# The test API access keys are described at www.degreedays.net/api/test
# They will let you access data from the Cape Cod area only.
# To fetch data from locations worldwide, sign up for a proper API account at
# www.degreedays.net/api/ and copy your API access keys here.
accountKey <- "test-test-test"
securityKey <- "test-test-test-test-test-test-test-test-test-test-test-test-test"

# You can call the API over HTTP using http://apiv1.degreedays.net/json or
# over HTTPS using https://apiv1.degreedays.net/json - set the endpoint URL
# below as appropriate.
endpoint <- "http://apiv1.degreedays.net/json"



# ************* STEP 1: Create the request ************************************
# First we create a JSON request that specifies what we want from the API.
# See www.degreedays.net/api/json#request for more on this. 
# In R we can do this by constructing an R object and converting it to JSON.

# You can fetch data from a station ID, a longitude/latitude position, or a 
# postal/zip code.
location <- list(
  type = "PostalCodeLocation",
  postalCode = "02532",
  countryCode = "US"
)
# In this example we fetch both HDD and CDD, using the same breakdown (daily
# data covering the last 7 days) for both. For more breakdown options see:
# www.degreedays.net/api/json#breakdown
breakdown <- list(
  type = "DailyBreakdown",
  period = list(
    type = "LatestValuesPeriod", 
    numberOfValues = 7
  )
)
locationDataRequest <- list(
  type = "LocationDataRequest",
  location = location,
  dataSpecs = list(
    # Here we specify 2 DataSpec items: one for HDD and one for CDD.  You
    # can specify up to 100 DataSpec items in one request (e.g. to fetch
    # data in lots of base temperatures).  With an API Standard+ account you
    # can have a DataSpec for hourly temperature data too.
    # Give each DataSpec a unique name so you can get the corresponding
    # DataSet from the response.
    myHDD = list(
      type = "DatedDataSpec",
      calculation = list(
        type = "HeatingDegreeDaysCalculation", 
        baseTemperature = list(
          unit = "F", 
          value = 60
        )
      ),
      breakdown = breakdown 
    ), 
    myCDD = list(
      type = "DatedDataSpec",
      calculation = list(
        type = "CoolingDegreeDaysCalculation",
        baseTemperature = list(
          unit = "F", 
          value = 70
        )
      ),
      breakdown = breakdown
    ) 
  )
)
fullRequest <- list(
  securityInfo = list(
    endpoint = endpoint,
    accountKey = accountKey,
    timestamp = strftime(as.POSIXlt(Sys.time(), "UTC"), "%Y-%m-%dT%H:%M:%SZ"),
    random = UUIDgenerate()
  ),
  request = locationDataRequest
)
fullRequestJson <- toJSON(fullRequest, auto_unbox = TRUE)
# Now our JSON request is ready.  Uncomment the line below to see the JSON:
# print(fullRequestJson)



# ************* STEP 2: Send the request to the API ***************************
# Next we sign the JSON request and package everything together into an HTTP
# request which we send to the Degree Days.net API.  This follows the spec at
# www.degreedays.net/api/json#send (though you can just copy/paste).
requestBytes <- charToRaw(enc2utf8(fullRequestJson))
signatureBytes <- hmac(charToRaw(enc2utf8(securityKey)), 
                       requestBytes, "sha256", raw = TRUE)
# The API requires the JSON request and the signature to be base64url encoded.
base64UrlEncode <- function(input) {
  base64 <- base64_enc(input)
  base64 <- gsub("+", "-", base64, fixed = TRUE)
  base64 <- gsub("/", "_", base64, fixed = TRUE)
  base64 <- gsub("=$", "", base64)
  return(base64)
}
# Prepare the HTTP request parameters to send to the API servers:
requestParameters <- list(
  request_encoding = "base64url",
  signature_method = "HmacSHA256",
  signature_encoding = "base64url",
  encoded_request = base64UrlEncode(requestBytes),
  encoded_signature = base64UrlEncode(signatureBytes)
)
# Send the HTTP request to the API servers using the httr library:
httpResponse <- POST(endpoint, body = requestParameters, encode = "form")



# ************* STEP 3: Process the response from the API *********************
# The JSON response is explained at www.degreedays.net/api/json#response
fullResponseJson <- content(httpResponse, "text")
# Uncomment the line below to see the JSON response:
# print(fullResponseJson)

# Use fromJSON to turn the JSON response into an R object:
fullResponse <- fromJSON(fullResponseJson)
# fullResponse$metadata has some rate-limit info, but we are mainly interested
# in fullResponse$response (a LocationDataResponse in this case).
response <- fullResponse$response

# Function to convert the ISO date-time strings in time-series data into POSIXct
# date-times, including the time-zone offset.  Note that POSIXct date-times in a
# data frame will automatically be displayed in the system time-zone.
convertIsoDateTimeToPosixct <- function(input) {
  lastChar <- substring(input, nchar(input), nchar(input))
  tzDate <- ifelse(lastChar == "Z", 
                   sub("Z","+0000", input),
                   sub(":([^:]*)$", "\\1", input))
  return(as.POSIXct(tzDate, format = "%Y-%m-%dT%H:%M%z"))
}

# Function to convert the ISO date-time strings in time-series data into chron
# date-times, in the local time-zone of the weather station.
convertIsoDateTimeToChron <- function(input) {
  date = substr(input, 0, 10)
  time = paste(substr(input, 12, 16), ":00", sep = "")
  return(chron(dates = date, times = time, 
               format = c(dates = "y-m-d", times = "h:m:s")))
}

# Function to extract the time-zone from an ISO date-time string.
extractTimeZone <- function(input) {
  offset <- substring(input, 17, nchar(input))
  return(paste("GMT", ifelse(offset == "Z", "", offset), sep = ""))
}

# Function to get a data frame from a DataSet object, including date and 
# date-time conversions to make it usable for analysis.
getUsableDataFrame <- function(dataSet) {
  if (dataSet$type == "AverageDataSet") {
    # Average data sets have annual and monthly values which can be combined
    # into a single data frame.
    dfMonthly <- as.data.frame(do.call(rbind, lapply(dataSet$monthly, 
                                                     as.data.frame)))
    dfAnnual <- as.data.frame(dataSet$annual)
    df <- rbind(dfMonthly, dfAnnual)
    row.names(df) <- c("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
                       "Sep", "Oct", "Nov", "Dec", "Total")
  } else {
    df <- dataSet$values
    # Date conversions
    if ("d" %in% colnames(df)) {
      # For daily data there will be a single date column "d", which we can 
      # convert from character to Date type.
      df$d <- as.Date(df$d, "%Y-%m-%d")
    }
    if ("ld" %in% colnames(df)) {
      # For non-daily data there will be an additional date column "ld" which is 
      # short for "last day". This can be converted in the same way.
      df$ld <- as.Date(df$ld, "%Y-%m-%d")
    }
    if ("dt" %in% colnames(df)) {
      # For time-series data (like hourly temperature data) the "dt" column
      # contains ISO date-time strings that include the time-zone of the weather
      # station.  We convert these into both POSIXct and Chron date-times, as
      # either or both of these may be useful in analysis.
      df$dt_chron_in_station_tz <- convertIsoDateTimeToChron(df$dt)
      df$dt_posixct_in_system_tz <- convertIsoDateTimeToPosixct(df$dt)
      df$station_tz <- extractTimeZone(df$dt)
      df$dt <- NULL
      df <- df[, c("dt_chron_in_station_tz", "station_tz", 
                   "dt_posixct_in_system_tz", "v", "pe")]
    }
  }
  if ("pe" %in% colnames(df)) {
    # A "pe" (percentage estimated) column will be present if any of the values
    # are estimated.  Values without a pe are 0% estimated (i.e. not estimated).
    df$pe[is.na(df$pe)] <- 0
  }
  return(df)
}

if (response$type == "Failure") {
  # See www.degreedays.net/api/json#failure for more about failures.
  print(paste("Request Failure: ", response$code, " - ", response$message))
} else {
  # The response contains a lot of useful info.  See above to view the JSON,
  # or check the JSON docs at www.degreedays.net/api/json#response
  print(paste("Station Id: ", response$stationId))
  # "myHDD" is the name we gave the HDD DataSpec in our request.
  hddData <- response$dataSets$myHDD
  if (hddData$type == "Failure") {
    print(paste("Failure for HDD Data:", hddData$code, "-", hddData$message))
  } else {
    hddData <- getUsableDataFrame(hddData)
    print("HDD data:")
    print(hddData)
  }
  cddData <- response$dataSets$myCDD
  if (cddData$type == "Failure") {
    print(paste("Failure for CDD Data:", cddData$code, "-", cddData$message))
  } else {
    cddData <- getUsableDataFrame(cddData)
    print("CDD data:")
    print(cddData)
  }
}

Packages

We use five packages in this sample code:

All the above packages can be installed using R's install.packages command, for example install.packages("httr"). Or you can use the package management tools within your IDE.

Problems?

Hopefully the example code above, the JSON API docs, and the JSON API test tool will be enough to get you going, but please feel free to email us if you'd like more help.

Higher level integration details

It is also worth reading the higher-level integration guide for tips on the various approaches to integrating with the API. We have helped a lot of businesses integrate their software with our API so we are very familiar with the patterns that work well for common use cases.

Choose your Plan and Sign Up Today!

© 2008–2021 BizEE Software – About | Contact | Privacy | Free Website | API | Integration Guide | API FAQ | API Sign-Up