This is a tiny bit of code that allows common lisp to fetchp data from the US’s National Climatic Data Center’s CLIMATE DATA ONLINE APIS, hence the mnemonic CDO.
You must register with an email address prior to using their API. Store the token you get as so: (setf (get :cdo-auth-info :token) “…your…token…”) If you like you can store that form in the file “auth.lisp” and the code will load that spontaneously.
There are weather stations at various locations that have collected assorted types of data over various intervals. The types of data fall into assorted categories.
;; Info for a single station.
(fetch "stations/coop:190166")
;; Stations in Massachusetts
(pprint (fetch :stations :limit 1 :fips 25))
;; Massachuesetts stations with min/max tempurature
(fetch :stations :datatypeid :emnt :datatypeid :emxt :locationid :fips:25")
;; Note that the meta data reports the total number of stations.
(pprint (fetch :stations :limit 1))
There are more than 100 thousand stations. Many of them are not currently active. You can query information about a single station. And you can pull data for stations in a given region using various schemes. You can also filter to get stations that have the types of data that you need. Apparently you can’t filter stations with data for a given time interval.
(fetch "locations/ZIP:02476")
(fetch "locations/FIPS:25")
(assoc :metadata (fetch :locations :limit 1))
(fetch :locations :locationcategoryid :ST :limit 52)
(fetch :locations :locationcategoryid :CITY :sortfield :name :sortorder :desc :offset 100 :limit 100)
(fetch :datatypes) First 25 of the set of ~1.5K data types
(pprint (fetch :datatypes :stationid "GHCND:US1MAMD0007")) 11 types available
(pprint (fetch :dataCategories :limit 100)) 41 categories
(fetch :data :datasetid :ghcnd :locationid "fips:02"
:startdate "2010-05-01" :enddate "2010-05-31")
(fetch '(:data ("datasetid" . "GHCND") ("locationid" . "FIPS:02")
("startdate" . "2010-05-01") ("enddate" . "2010-05-31")
("datatypeid" . "prcp") ("datatypeid" . "SNWD")))
The API can be slow, sometimes quite slow. The data provided by this API is reasonably static, so memoizing or caching the fetch routine might help with that.
The API doesn’t report errors very well. Sometimes it ignore parameters you have passed. This is bogus:
(equal (fetch :stations :limit 1 :maxdate "2014-03-28")
(fetch :stations :limit 1 ))
--> T
And sometimes it just returns an empty result when your query is malformed.