Welcome!
In this rightmost column, you’ll see example API calls and responses.
Plenario is a centralized hub for open datasets from around the world, ready to search and download.
The Plenario API can be used to perform custom geospatial and temporal queries.
A few things to know:
- All API calls should be made with
HTTP GET
- All methods are accessed via:
http://plenar.io/v1/api/<ENDPOINT>
- All API responses default to JSON format, but you can specify alternate formats specific to some endpoints.
Concepts
There are a few basic concepts to keep in mind as you work with the Plenario API.
Space and time
Filtering datasets by political boundaries
plenar.io/v1/api/detail/?dataset_name=crimes_2001_to_present&shape=boundaries_neighborhoods&boundaries_neighborhoods__filter={"op": "eq", "col": "pri_neigh", "val": "Logan Square"}
plenar.io/v1/api/detail/?dataset_name=food_inspections&shape=boundaries_neighborhoods&boundaries_neighborhoods__filter={"op": "eq", "col": "pri_neigh", "val": "Logan Square"}
All data in Plenario is spatial. If it’s in Plenario, you can put it on a map. Because Plenario makes sure all of its data lives on the same map, you can apply common spatial operations to different datasets. For example, you can take two datasets - crimes and food inspections in Chicago - and extract only the events that happened in the neighborhood of Logan Square.
Creating timeseries aggregated by day
plenar.io/v1/api/timeseries/?obs_date__ge=2015-10-12&obs_date__le=2015-11-12&dataset_name__in=crimes_2001_to_present,food_inspections&agg=day
Many - but not all - of Plenario’s datasets also have a temporal component. Similarly, Plenario makes sure those datasets live on the same timeline. That makes it easy to aggregate datasets up to the same temporal unit and compare trends.
Dataset Types
Plenario currently supports three types of datasets: event datasets, shape datasets, and sensor network datasets. The type of a dataset lets you know what kind of spatial and temporal information it is guaranteed to have.
See all event datasets in Plenario
plenar.io/v1/api/datasets
Events
All records in event datasets have a temporal component (a point in time) and a spatial component (a point in space). For example, every record in the Chicago food inspections dataset represents one inspection. An inspector walked into a restaurant - represented as a latitude longitude point - at a time - represented as a timestamp.
Of course, a point and a timestamp are just the minimum information event datasets need. For example, the food inspections dataset also has a column with the name of the restaurant that was inspected and another column for whether the restaurant passed the inspection.
See all shape datasets in Plenario
plenar.io/v1/api/shapes
Shapes
All records in shape datasets have a spatial component. While events are always tied to a point in space, shape datasets can have different spatial types, like polygons to represent neighborhood boundaries or line segments to represent bike routes. Shape datasets do not have a temporal component.
Shape datasets usually have extra columns that aren’t spatial. For example, the shape dataset with the borders of Chicago’s neighborhoods has a column with the neighborhoods’ names.
See all sensor networks in Plenario
plenar.io/v1/api/sensor-networks
Sensor Networks
Sensor networks are collections of sensor nodes that report on physical phenomena like temperature, air quality, or traffic. In particular, Plenario reports observations from Chicago’s Array of Things sensor network. Sensor observations have a spatial component (a node’s location) and a temporal component (when the observation was taken).
Datasets That Don’t Fit
You can probably think of examples of spatial datasets that don’t fit the above types. What about neighborhood unemployment rates? That has a static spatial component plus a timeseries. Or urban bike share trips? A single record should have a point in space and a timestamp for both the origin and the destination. We can’t support these fully yet, but we’re always working to expand the types of datasets Plenario can handle.
Event & Shape Data
Because Event and Shape datasets are similar in structure (they’re both tabular) they share many of the same query options. We cover them together in this section.
Sensor network data, on the other hand, is not tabular. It comes in to Plenario as a stream of data, not a tabular file. So queries against sensor networks look a bit different, and will be covered in the next section
Query Syntax
– Time Filtering
Query over 2015
&obs_date__ge=2015-1-1&obs_date__le=2015-12-31
For endpoints that accept temporal filters, you can provide the query parameters obs_date__ge
(observation date greater than or equal to) and obs_date__le
(less than or equal to). Both must be formatted as YYYY-MM-DD.
parameter | description | default |
---|---|---|
obs_date__ge |
start of date range | 90 days ago |
obs_date__le |
end of date range | today |
– Space Filtering
Query over the author’s block
location_geom__within={"type":"Polygon","coordinates":[[[-87.58695602416992,41.79224063145134],[-87.58695602416992,41.7996633276003],[-87.5745964050293,41.7996633276003],[-87.5745964050293,41.79224063145134],[-87.58695602416992,41.79224063145134]]]}
For endpoints that accept spatial filters, you can provide the location_geom__within
parameter.
It must be a URL encoded GeoJSON polygon or multipolygon.
– Specifying a Dataset
Many endpoints require you to specify a dataset to query.
In that case, specify the dataset_name
query parameter.
If you can specify more than one dataset, you can use dataset_name__in
to provide a list of dataset names.
– Asynchronous Jobs
You can invoke the Jobs interface by appending
job=true
to your query.
http://plenar.io/v1/api/datasets?job=true
This will return a jobs ticket instead of the usual datasets endpoint. You can then use the link provided by the ticket to access the job status and results.
You can add job=true
to launch a query as an asynchronous job.
Plenario will run your query as a background task
and give you a ticket.
You can check on your job’s progress at /v1/api/jobs/{ticket}
.
When the job is complete, /v1/api/jobs/{ticket}
will contain the result of your job in the result
field.
This can be useful when you want to launch a very large query against Plenario, like aggregating a large event dataset over a large shape dataset. It might take too long for Plenario to process a massive request in a synchronous HTTP call. If you notice that a call is timing out, try running it as an asynchronous job instead.
– Attribute Operators
Use the “columns” information from each dataset’s metadata to find the name
...
"columns": [
{
"field_type": "DOUBLE PRECISION",
"field_name": "shape_area"
},
{
"field_type": "VARCHAR",
"field_name": "pri_neigh"
},
{
"field_type": "VARCHAR",
"field_name": "sec_neigh"
},
{
"field_type": "DOUBLE PRECISION",
"field_name": "shape_len"
}
], ...
When you make a query against a specific dataset,
you can filter against that dataset’s attributes.
You can find out the name and types of each dataset’s attributes
through the event and shape metadata endpoints. For a detailed list of all field_type
options, consult the table at the bottom of this PostgreSQL documentation.
You can use the following binary operators:
LIKE examples:
“%rat%” matches “rat poisoning” and “crater”. “jo_” matches “joe” and “job” but not “josephine”
operator | description |
---|---|
eq |
equal to (==) |
gt |
greater than (>) |
ge |
greater than or equal to (>=) |
lt |
less than (<) |
le |
less than or equal to (<=) |
ne |
not equal (!=) |
in |
within a list of provided values like 0560,0110 |
like |
Match string pattern |
ilike |
Match string pattern, case insensitive |
– Attribute Filtering
Filter Chicago Department of Health complaints to only return records with the word “asbestos” in the complaint description
{"op":"ilike", "col":"complaint_detail", "val":"%asbestos%"}
A single conditions that applies to one feature can be expressed in the following syntax: {"op":"<operator>", "prop":"<property>", "val":"<target_value>"}
Filter Chicago crimes dataset to only include narcotics crimes that took place on a street or sidewalk
{"op": "and", "val": [
{"op": "eq", "col": "primary_type", "val": "NARCOTICS"},
{"op":"or", "val": [
{"op":"eq","col":"location_description","val":"STREET"},
{"op":"eq","col":"location_description","val":"SIDEWALK"}
]}
]
}
You can also apply ANDs and ORs to conditions with the following syntax:
{"op": <"and" or "or">, "val": [<list of conditions>]}
. You can nest conditions arbitrarily deep.
Applying filters to the Chicago crimes and Chicago neighborhoods datasets to return homicides from Logan Square and Humboldt Park
plenar.io/v1/api/detail/?dataset_name=crimes_2001_to_present&crimes_2001_to_present__filter={"op": "eq", "col": "primary_type", "val": "HOMICIDE"}&shape=boundaries_neighborhoods&boundaries_neighborhoods__filter={"op": "in", "col": "pri_neigh", "val": "Logan Square,Humboldt Park"}
You can specify filters as query parameters in your GET requests as <dataset_name>__filter={filter}
.
You need to specify which dataset a filter applies to because a single query might include more than one dataset.
– Attribute Filtering (Old Syntax)
This syntax is deprecated.
pri_neigh__in=%3DLogan%20Square%2CHumboldt%20Park
The original method for applying conditions to attributes of a dataset
is to provide one query parameter for each condition in the form of
[col]__[op]=[val]
.
The trouble with this syntax is that you can’t specify
whether you want to combine the conditions with ANDs or ORs.
So this syntax assumes you just want to AND things together.
You also can’t specify which dataset a condition should apply to.
Response Format
All JSON API responses return their data in the objects
block. Additional information is returned in the meta
block:
Parameter | Description |
---|---|
status | ok if the query is successful, error if not. |
query | Original query parameters passed in. |
message | If status is error, a detailed message as to what went wrong. |
Metadata Endpoints
– Event Datasets
GET /v1/api/datasets/
Example Query
http://plenar.io/v1/api/datasets
List of all event datasets.
Example Response
{
"meta": {
"status": "ok",
"query": { },
"message": [
[ ]
],
"total": 118
},
"objects": [
{
"attribution": "Los Angeles Police Department",
"description": "LAPD Crime and Collision Raw Data for 2013",
"view_url": "https://data.lacity.org/api/views/iatr-8mqm/rows",
"columns": [
{
"field_type": "VARCHAR",
"field_name": "status"
},
{
"field_type": "DATE",
"field_name": "date_occ"
},
...
],
"last_update": "2015-04-17T19:30:44.922015",
"obs_from": "2013-01-01",
"bbox": {
"type": "Polygon",
"coordinates": [
[
[
-117.7071,
33.706
],
...
]
]
},
"human_name": "LAPD Crime and Collision Raw Data for 2013",
"obs_to": "2013-12-31",
"date_added": "2015-04-17T19:30:44.922015",
"source_url": "https://data.lacity.org/api/views/iatr-8mqm/rows.csv?accessType=DOWNLOAD",
"dataset_name": "lapd_crime_and_collision_raw_data_for_2013",
"update_freq": "yearly"
},
]
}
Used to list available event datasets and fetch their metadata.
Bounding Boxes
Each event dataset’s metadata contains a spatial and temporal bounding box, the smallest timespan and rectangle in which all events in the dataset are contained. If you apply spatial or temporal filters to this endpoint, it will only return datasets with events that fell within your filters. It is often helpful to use these bounding boxes to narrow down a search over all the datasets in Plenario.
Common Query Syntax
By default, this endpoint returns every available event dataset.
Parameter Name | Required? | Default |
---|---|---|
dataset_name/dataset_name__in | no | none |
location_geom__within | no | none |
obs_date__ge & obs_date__le | no | none |
Response
One record per event dataset.
Attribute Name | Attribute Description |
---|---|
attribution | The data provider |
description | Verbose, official description of the dataset. |
view_url | A URL where you can learn more about the dataset. |
columns | Name and type of each column. |
obs_from | Oldest date available in the dataset. |
bbox | The smallest rectangle that contains every event in this dataset. (GeoJSON polygon) |
human_name | Human-friendly name for the dataset. |
obs_to | Newest date available in the dataset. |
source_url | If available, the URL where the data was originally sourced. |
dataset_name | Machine name for the dataset. The name you need to supply in other endpoints. |
update_freq | How often Plenario checks the source dataset for updates. |
– Shape Datasets
GET /v1/api/shapes
Example Query
http://plenar.io/v1/api/shapes/
This query yields information about every shape dataset.
Example Response
{
"meta": {
"status": "ok",
"message": ""
},
"objects": [
{
"attribution": "City of Chicago",
"description": "Major streets in Chicago. ",
"view_url": "",
"num_shapes": 16065,
"source_url": "https://data.cityofchicago.org/download/ueqs-5wr6/application/zip",
"bbox": "{\"type\":\"Polygon\",\"coordinates\":[...]}",
"date_added": "2016-04-20",
"human_name": "Major Streets",
"dataset_name": "major_streets",
"update_freq": "yearly",
"columns": [{"field_type": "VARCHAR", "field_name": "street_nam"},{"field_type": "VARCHAR", "field_name": "direction"}, ...]
},
...
]
}
Used to list available shape datasets and fetch their metadata.
Bounding Boxes
Each shape dataset’s metadata contains a spatial bounding box,
the smallest rectangle in which all shapes in the dataset are contained.
If you apply a spatial filter to this endpoint,
it only returns datasets with shapes within the box.
Furthermore, the num_shapes
response parameter will only
count the shapes that were contained by or intersected your filter.
Common Query Syntax
Specify location_geom_within
to only view metadata about shape datasets in a particular area.
Parameter Name | Required? | Default |
---|---|---|
location_geom_within | no | None |
Responses
One record per shape dataset.
Attribute Name | Attribute Description |
---|---|
attribution | The data provider |
description | Verbose, official description of the dataset. |
source_url | If available, the URL where the data was originally sourced. |
date_added | the date the shape dataset was added to Plenario |
human_name | a nicer name to refer to the shape dataset in user interfaces |
dataset_name | the name by which you can query the shape dataset |
update_freq | Update frequency |
columns | Name and type of each column. |
– Dataset Fields
GET /v1/api/fields/<dataset_name>/
Example Query
http://plenar.io/v1/api/fields/crimes_2001_to_present/
Field definitions for Chicago crime report dataset
This endpoint is deprecated in favor of /datasets
.
Given an event dataset name, return all fields and their types.
Gives you a listing of all the fields and their data types for the given dataset.
Query Parameters
This API endpoint has no query parameters.
Response
Example Response
{
"meta": {
"status": "ok",
"query": { },
"message": [
[ ]
],
"total": 1
},
"objects": [
{
"field_type": "INTEGER",
"field_name": "y_coordinate"
},
{
"field_type": "INTEGER",
"field_name": "year"
},
{
"field_type": "BOOLEAN",
"field_name": "domestic"
},
...
]
}
Attribute Name | Attribute Description |
---|---|
field_type | Postgres data type for given field. |
field_name | Name of database field. Useful for performing additional queries using the /v1/api/detail-aggregate/ and /v1/api/detail/ endpoints. |
Event Data Queries
– Event Records
GET /v1/api/detail
All Chicago homicides since May 1st, 2016
http://plenar.io/v1/api/detail/?dataset_name=crimes_2001_to_present&obs_date__ge=2016-5-1&crimes_2001_to_present__filter={"op": "eq", "col": "primary_type", "val": "HOMICIDE"}
{
"meta": {
"status": "ok",
"query": {
"obs_date__ge": "2016-05-01",
"data_type": "json",
"obs_date__le": "2016-07-01T14:49:32.720091",
"iucr": "0110",
"dataset": "crimes_2001_to_present",
"shape": null,
"geom": null,
"offset": 0,
"metatable": "meta_master"
},
"message": [ ],
"total": 121
},
"objects": [
{
"id": 22444,
"case_number": "HZ247790",
"date": "2016-05-02T01:35:00",
"block": "059XX N RIDGE AVE",
"iucr": "0110",
"primary_type": "HOMICIDE",
"description": "FIRST DEGREE MURDER",
"location_description": "STREET",
"arrest": false,
"domestic": false,
"beat": 2012,
"district": 20,
"ward": 40,
"community_area": "77",
"fbi_code": "01A",
"x_coordinate": 1164091,
"y_coordinate": 1939858,
"year": 2016,
"updated_on": "2016-05-09T15:51:54",
"latitude": 41.990596764,
"longitude": -87.671796648,
"location": "(41.990596764, -87.671796648)"
},
...
]
}
Query an event dataset and get back the raw individual records.
– Common Query Syntax
Parameter Name | Required? | Default |
---|---|---|
dataset_name | yes | n/a |
location_geom__within | no | none |
obs_date__ge & obs_date__le | no | 90 days ago - today |
[dataset_name]__filter | no | none |
Endpoint-Specific Parameters
Parameter Name | Parameter Default | Parameter Description |
---|---|---|
data_type | json | Response data format. Current options are json , geojson and csv |
shape | none | Filter with a shape dataset |
offset | none | Used to paginate through results of more than 1000. Example: offset=1000 will fetch the second page of results. |
limit | 1000 | Set a custom limit on the amount of records returned; maximum is 10,000 |
Responses
See right. The API responds with a list of raw records for the particular dataset. The
fields returned will vary per dataset. By default, the response is limited to 1000 results; the absolute maximum is 10,000 results, so set a custom limit
within those bounds if necessary. These results can still be paginated by using the offset
parameter.
Attribute Name | Attribute Description |
---|---|
status | Indicates query success, can be ok or error . |
query | Shows values used in the query. |
message | Reports errors or warnings (if any). |
total | Total number of records found. |
objects | Contains records |
Filtering with a Shape Dataset
Only return events that happened in Logan Square
&shape=boundaries_neighborhoods&boundaries_neighborhoods__filter={"op": "eq", "col": "pri_neigh", "val": "Logan Square"}
Use the shape
parameter to specify the name of a shape dataset.
Then the endpoint will only return events
that intersect or are contained by shapes in the dataset.
This feature is particularly useful when you apply filters to the dataset
by adding a <shape_dataset_name>__filter
parameter.
For example, you can specify the Chicago neighborhoods shape dataset
and specify a neighborhood in your filter to only fetch events from one neighborhood.
Response Formatting
By default, this endpoint returns data exactly as it was written in the source dataset.
Behind the scenes, Plenario parses event datasets’ latitude and longitude columns
to produce a geometry column that it uses internally.
If you want to get the geometry Plenario has parsed,
use the data_type
parameter to specify geojson
.
Plenario will return each record as a GeoJSON point with the parsed latitude and longitude in the coordinates
object and the original values in the attributes
object.
– Bulk Export
GET /v1/api/datadump
Because the raw data endpoint /detail
is designed to respond quickly,
it is limited to 1000 observations. If you want to download all records
of an event dataset that meet the filter you have provided, you can
request a bulk export with /datadump
.
/datadump
takes the same query parameters as /detail
.
Shape Data Queries
– Shape Records
GET /v1/api/shapes/<dataset_name>
Example Queries
Get a GeoJSON document with Chicago’s streets that are reserved for pedestrian traffic. Filter so that only those set aside for retail are included.
http://plenar.io/v1/api/shapes/pedestrian_streets/?data_type=json&pedestrian_streets__filter={"op": "eq", "col": "name", "val": "PEDESTRIAN STREET RETAIL"}
Request shapes from a shape dataset. Returns all records in the dataset by default. You can also apply a spatial filter or filter on attributes to request a subset.
Common Query Syntax
Parameter Name | Required? | Default |
---|---|---|
location_geom__within | no | none |
[dataset_name]__filter | no | none |
Endpoint-Specific Parameters
Parameter Name | Parameter Default | Parameter Description |
---|---|---|
data_type | json |
json for GeoJSON, shapefile for ESRI Shapefile, or kml for KML |
Temporal Aggregation
– Timeseries
GET v1/api/timeseries
Generate counts of crime and environmental complaints per year from 2010 to 2015.
http://plenar.io/v1/api/timeseries/?obs_date__ge=2010-1-1&obs_date__le=2015-12-31&dataset_name__in=crimes_2001_to_present,cdph_environmental_complaints&agg=year
{
"meta": {
"status": "ok",
"query": {
"obs_date__ge": "2007-11-12",
"data_type": "json",
"obs_date__le": "2008-11-12",
"agg": "year",
"dataset": null,
"dataset_name__in": [
"crimes_2001_to_present",
"cdph_environmental_complaints"
],
"geom": null
},
"message": [ ]
},
"objects": [
{
"dataset_name": "cdph_environmental_complaints",
"count": 6836,
...
"items": [
{
"count": 1262,
"datetime": "2010-01-01"
},
{
"count": 1460,
"datetime": "2011-01-01"
},
{
"count": 1032,
"datetime": "2012-01-01"
},
{
"count": 1187,
"datetime": "2013-01-01"
},
{
"count": 1074,
"datetime": "2014-01-01"
},
{
"count": 821,
"datetime": "2015-01-01"
}
],
},
{
"dataset_name": "crimes_2001_to_present",
...
"count": 429324,
"items": [
{
"count": 370092,
"datetime": "2010-01-01"
},
{
"count": 351483,
"datetime": "2011-01-01"
},
{
"count": 335602,
"datetime": "2012-01-01"
},
{
"count": 306603,
"datetime": "2013-01-01"
},
{
"count": 274258,
"datetime": "2014-01-01"
},
{
"count": 261662,
"datetime": "2015-01-01"
}
],
}
]
}
This endpoint creates timeseries over one or more event datasets
by counting how many events fall into each time slice.
You can set the unit of aggregation with the agg
parameter.
Common Query Syntax
Parameter Name | Required? | Default |
---|---|---|
dataset_name/dataset_name__in | no | every event dataset |
location_geom__within | no | none |
obs_date__ge & obs_date__le | no | 90 days ago - today |
[dataset_name]__filter | no | none |
Endpoint-Specific Parameters
Parameter Name | Parameter Default | Parameter Description |
---|---|---|
agg | week | Time resolution to aggregate observation counts by. Supported values:
|
data_type | json | Response data format. Current options are json and csv . |
Response
The API responds with a list of datasets with a dense matrix of counts grouped
by temporal aggregation.
The actual timeseries values are inside of items
.
Many of the metadata attributes from /datasets
are included as well.
Attribute Name | Attribute Description |
---|---|
status | Indicates query success, can be ok or error . |
query | Shows values used in the query. |
message | Reports errors or warnings (if any). |
dataset_name | The dataset this timeseries was created from. |
count | Total number of records found. |
datetime | Date of aggregation |
items | Counts of aggregated records and delimiting datetimes. |
Deprecated Version
GET v1/api/detail-aggregate/
This endpoint is deprecated in favor of /timeseries
http://plenar.io/v1/api/detail-aggregate/?agg=year&dataset_name=crimes_2001_to_present&obs_date__ge=2012-1-1
Just like /timeseries
,
except that it requires exactly one dataset through the dataset_name
parameter.
Spatial Aggregation
– Heat Map
GET v1/api/grid
Heat map of Chicago 311 tree trim requests in 2014
http://plenar.io/v1/api/grid/?obs_date__ge=2014-01-01&obs_date__le=2014-12-31&dataset_name=311_service_requests_tree_trims
{
"type":"FeatureCollection",
"features":[
{
"geometry":{
"type":"Polygon",
"coordinates":[
[
[
-87.69635961403962,
41.876826253090584
],
[
-87.69635961403962,
41.88132164531356
],
[
-87.70239743700178,
41.88132164531356
],
[
-87.70239743700178,
41.876826253090584
],
[
-87.69635961403962,
41.876826253090584
]
]
]
},
"type":"Feature",
"properties":{
"count":7
}
}
...
]
}
Create a GeoJSON grid heatmap from an event dataset. See example grid heatmaps in the Plenario explorer.
Common Query Syntax
Parameter Name | Required? | Default |
---|---|---|
dataset_name | yes | n/a |
location_geom__within | no | none |
obs_date__ge & obs_date__le | no | 90 days ago - today |
[dataset_name]__filter | no | none |
Query Parameters
All query parameters are optional except for dataset_name
.
Parameter Name | Parameter Default | Parameter Description |
---|---|---|
resolution | 500 | Square grid size (in meters). |
buffer | 100 | If location###within is a GeoJSON LineString, the size of the buffer around that line to query (in meters). |
Response
See right. Plenario will output a GeoJSON with a feature for each grid square containing
a count
property of the number of observations within that square.
– Choropleth
GET /v1/api/shapes/<polygon_dataset_name>/<point_dataset_name>/
Count the number of historical landmarks in each Chicago neighborhood.
http://plenar.io/v1/api/shapes/boundaries_neighborhoods/individual_landmarks?obs_date__ge=1900-09-22
{
"type": "FeatureCollection",
"features": [
{
"geometry": {
"type": "MultiPolygon",
"coordinates": [...]
},
"type": "Feature",
"properties": {
"shape_area": 48492503.1554,
"pri_neigh": "Grand Boulevard",
"sec_neigh": "BRONZEVILLE",
"shape_len": 28196.837157,
"count": 9
}
...
},
]
}
Given an event dataset and a polygon dataset, return a document of all of the
polygons in the polygon dataset together with the counts of the points that
intersect them.
Like /grid
, except using shapes defined in Plenario as opposed to an automatically generated grid.
Returns GeoJSON by default.
Query Parameters
Parameter Name | Parameter Default | Parameter Description |
---|---|---|
data_type | geojson | Response data format. Current options are geojson and csv . |
Sensor Network Data
A sensor node (represented as GeoJSON)
{
"geometry": {
"type": "Point",
"coordinates": [
-87.6298,
41.8781
]
},
"type": "Feature",
"properties": {
"info": {
"orientation": "NE",
"height_in_meters": "5"
},
"sensors": ["tmp421", "hmc5883l"],
"network_name": "array_of_things",
"id": "011"
}
}
Plenario lets you fetch data from sensor networks in different ways, depending on the needs of your application.
If you’re developing an application to let people explore data (like OpenGrid or Plenario’s demonstration application) the query and aggregate endpoints are designed to respond quickly, making them a good fit for web applications.
If you want to mirror the data from a network, you can use our Websocket API to receive all of a network’s data as it arrives in Plenario. The Websocket API is also helpful for applications that send real-time notifications and for real-time dashboards.
And if you want a bulk export to load into your own database, you can use our download endpoint to specify the time period and sensors you’re interested in, and Plenario will generate a flat file with that data.
Sensor Network Structure
A feature of interest with a single observed property
{
"name": "temperature",
"observed_properties": [
{
"type": "float",
"name": "temperature",
"unit": "Degrees Celsius",
"description": "external air temperature"
}
]
}
A feature of interest with three observed properties, representing a three-dimensional magnetic field vector
{
"name": "magnetic_field",
"observed_properties": [
{
"type": "float",
"name": "x",
"unit": "gauss"
},
{
"type": "float",
"name": "y",
"unit": "gauss"
},
{
"type": "float",
"name": "z",
"unit": "gauss"
}
]
}
To make queries against sensor networks, it will help to understand how Plenario structures sensor data. It uses the hierarchy of a network to let you drill down to the data you want to see, filtering by type of sensor, location of nodes, and more.
Each sensor network in Plenario has nodes, devices installed at some physical location. Nodes have sensors that report on physical properties like temperature. Sensors report observations that contain a timestamp and one or more values.
To make it easier to query across different sensors,
Plenario uses the concept of features of interest.
Features of interest define properties that different sensors can report on.
For example, if the tempy9000
and tempmaster_mach2
sensors both report on temperature,
you can query on the temperature
feature of interest to find temperature observations
instead of finding and specifying every temperature sensor in the network.
Features of interest also define the meaning of observations.
So you’re guaranteed that two sensors reporting under temperature
will have the same unit of measurement (Celsius).
Querying Data
A sensor observation, reporting on
magnetic_field
.
{
"feature_of_interest": "magnetic_field",
"node_id": "029",
"sensor": "hmc5883l",
"meta_id": 11,
"results": {
"x": 0.602,
"y": 0.613,
"z": 0.604
},
"datetime": "2016-12-25T00:54:18"
}
You can query sensor data much like you can query tabular data, filtering by time and space and performing aggregations. Unlike tabular data, you can also stream incoming sensor data over Websockets.
Querying Metadata
You can also query metadata - networks, nodes, sensors, and features of interest. The existing metadata endpoints tells you everything you need to know to form a valid data query - What are all the nodes that have ever been in this network? What are all the sensors that have ever been installed on a node?
Currently in development is support for more detailed metadata that lets you dig in to how an observation was derived - What constants were used to calibrate this sensor at the time of this observation? What sensors were installed on this node at the time of this observation?
Common Query Syntax
Query over January 2017
&start_datetime=2017-1-1&end_datetime=2017-2-1
For endpoints that allow time filtering, you can provide the query parameters start_datetime
(observation date greater than or equal to) and end_datetime
(less than or equal to). Both must be formatted in ISO 8601 format (YYYY-MM-DDThh:mm:ss, to whatever precision you desire).
Note that sensor observations are reported in
Coordinated Universal Time (UTC).
parameter | description | default |
---|---|---|
start_datetime |
start of date range | 90 days ago |
end_datetime |
end of date range | now |
Metadata Queries
The sensor network metadata endpoints give you all the information you need
to construct valid queries on sensor data.
Note that the metadata from these endpoints doesn’t necessarily
represent the current configuration of each sensor network.
For example, if a node is up for a year and then removed,
that node will still be visible in the /nodes
endpoint.
That way, you can still find it and query the data collected while it was up.
Similarly, if a sensor is removed from a node,
that sensor will still be visible in that node’s sensors
property.
Responses
Attribute Name | Attribute Description |
---|---|
query | Shows values used in the query. |
message | Reports warnings (if any). |
total | Total number of records found. |
data | Contains records |
error | Contains any errors |
Either the data or error field will be returned, but not both.
– Sensor Networks
sensor-networks/<network>
Retrieve metadata about one or many sensor networks that publish observations to Plenario. If no network is specified, metadata for all sensor networks will be returned.
Network metadata for the array_of_things sensor network
http://plenar.io/v1/api/sensor-networks/array_of_things_chicago
{
"meta": {
"query": {
"network": "array_of_things_chicago"
},
"message": [ ],
"total": 1
},
"data": [
{
"sensors": [
"TMP112"
],
"info": { },
"nodes": [
"000",
"011"
],
"features": [
"temperature"
],
"name": "array_of_things_chicago"
}
]
}
A sensor network is a collection of sensor nodes maintained by one organization. Within a sensor network’s metadata, you can find the IDs of nodes within the network and all of the features of interest those nodes report on. With this information, you can launch queries on features of interest or drill down further into the metadata by node.
Responses
Attribute Name | Attribute Description |
---|---|
name | Sensor network name. |
info | JSON containing any information provided by the network maintainer. |
nodes | Array of node IDs for all nodes within the network. |
sensors | Array of all sensor models within the network. |
features | Array of all features of interest that the network measures. |
– Nodes
GET /v1/api/sensor-networks/<network>/nodes/<node>
Retrieve metadata about nodes in a sensor network.
Nodes are formatted as GeoJSON,
with non-spatial metadata stored in the each node’s properties
object.
Node metadata for node 011 in the array_of_things network
http://plenar.io/v1/api/sensor-networks/array_of_things_chicago/nodes/011
{
"meta": {
"query": {
"network": "array_of_things_chicago"
},
"message": [],
"total": 1
},
"data": [
{
"geometry": {
"type": "Point",
"coordinates": [
41.9084,
-87.6214
]
},
"type": "Feature",
"properties": {
"info": {},
"sensors": [
"tmp112"
],
"network": "array_of_things_chicago",
"id": "011"
}
},
...
]
}
Node metadata for all nodes in the array_of_things network within the given geometry
http://plenar.io/v1/api/sensor-networks/array_of_things_chicago/nodes/?geom={"type":"Polygon","coordinates”:[[[40.0, -90.0],[45.0, -90.0],[45.0, -85.0],[40.0, -85.0]]]}
{
"meta": {
"query": {
"geom": {"type": "Polygon", "coordinates": [[[40.0, -90.0], [45.0, -90.0], [45.0, -85.0], [40.0, -85.0]]]},
"network": "array_of_things_chicago"
},
"message": [ ],
"total": 5
},
"data": [
{
"geometry": {
"type": "Point",
"coordinates": [
-87.623177,
41.881832
]
},
"type": "Feature",
"properties": {
"info": null,
"sensors": [
"sensor_dev_1",
"sensor_dev_4"
],
"id": "node_dev_1",
"network": "array_of_things_chicago"
}
}
]
}
A node is a collection of one or more sensors reporting from a fixed location. Each node belongs to exactly one network.
Get metadata about all nodes in a network,
sensor-networks/<network>/nodes
a specific node,
sensor-networks/<network>/nodes/<node>
or all nodes in a network within some geometry .
sensor-networks/<network>/nodes?geom=<geojson>
Common Query Syntax
Parameter Name | Required? | Default |
---|---|---|
geom | no | none |
Responses
Attribute Name | Attribute Description |
---|---|
id | Node identifier. |
network_name | Name of the network that maintains the node. |
info | JSON containing any information provided by the network maintainer. |
geometry | GeoJSON object giving the node’s location. |
sensors | Array of all sensors that the node has contained. |
– Features of Interest
GET /v1/api/sensor-networks/<network>/features/<feature>
Retrieve features of interest defined within a network.
If no feature is specified, the default is to return metadata for all features of interest within the network
Feature of interest metadata for magnetic_field
http://plenar.io/v1/api/sensor-networks/array_of_things_chicago/features/magnetic_field
{
"meta": {
"query": {
"network": "array_of_things",
"features": [
"magnetic_field"
]
},
"message": [],
"total": 1
},
"data": [
{
"name": "magnetic_field",
"observed_properties": [
{
"type": "float",
"name": "x",
"unit": "gauss"
},
{
"type": "float",
"name": "y",
"unit": "gauss"
},
{
"type": "float",
"name": "z",
"unit": "gauss"
}
]
}
]
}
An observation of magnetic_field
{
"feature": "magnetic_field",
"node": "029",
"sensor": "hmc5883l",
"meta_id": 11,
"results": {
"x": 0.602,
"y": 0.613,
"z": 0.604
},
"datetime": "2016-12-25T00:54:18"
}
A feature of interest defines properties of the world that sensors observe,
like temperature or traffic.
Every observation is tagged with a feature of interest,
which determines how the observation is formatted.
A feature called traffic_count
might be composed of observed properties
called pedestrians
, cars
, and bicycles
.
Then an observation of traffic_count
can only report values labeled
pedestrians
, cars
, and bicycles
.
A feature of interest must have one or more observed properties.
Observed properties contain metadata like
data type (float, int, boolean, or string) and unit of measurement that can help you interpret observations.
Properties only define scalar values, so for features that are vector-valued,
you will find each dimension defined as a separate feature.
For example, the definition of magnetic_field
to the right
has separate properties for the x, y, and z dimensions.
Common Query Syntax
Parameter Name | Required? | Default |
---|---|---|
geom | no | none |
Responses
Attribute Name | Attribute Description |
---|---|
name | Feature of interest name. |
properties | Array of JSON objects containing property names, types, units, and any other necessary description. |
– Sensors
GET /v1/api/sensor-networks/<network>/sensors/<sensor>
Sensor metadata for sensor model TMP112
Retrieve metadata about sensors. If no sensor is specified, returns all sensors from the specified network.
http://plenar.io/v1/api/sensor-networks/array_of_things_chicago/sensors/TMP112
{
"meta": {
"query": {
"network": "array_of_things",
"sensor": "tmp112"
},
"message": [ ],
"total": 1
},
"data": [
{
"info": { },
"name": "tmp112",
"properties": [
"temperature.temperature"
]
}
]
}
A sensor is a piece of equipment that generates observations.
Every observation is tagged with the sensor that generated it.
The info
object in sensor metadata contains general metadata
like a link to the sensor’s datasheet.
The properties
list contains all of the observed_properties
that the sensor reports on, written as
Common Query Syntax
Parameter Name | Required? | Default |
---|---|---|
geom | no | none |
Responses
Attribute Name | Attribute Description |
---|---|
name | Name of sensor model. |
info | JSON containing any information provided by the network maintainer. |
properties | Array of properties measured by the sensor in the format feature .property |
– Map
Map the array_of_things_chicago network
http://plenar.io/v1/api/sensor-networks/array_of_things_chicago/map
{
"0000001e0610b9e7": {
"apds-9006-020": {
"light_intensity.500nm": "intensity"
},
"bmi160": {
"acceleration.x": "accel_x",
"acceleration.y": "accel_y",
"acceleration.z": "accel_z",
"orientation.x": "orient_x",
"orientation.y": "orient_y",
"orientation.z": "orient_z"
}
},
"0000001e0610ba72": {
"apds-9006-020": {
"light_intensity.500nm": "intensity"
},
"bmi160": {
"acceleration.x": "accel_x",
"acceleration.y": "accel_y",
"acceleration.z": "accel_z",
"orientation.x": "orient_x",
"orientation.y": "orient_y",
"orientation.z": "orient_z"
}
}
}
GET /v1/api/sensor-networks/<network>/map
Represents the specified network as a tree. This can be helpful when it is necessary to programmatically explore the contents of a network or to see the relationships of its subcomponents.
– Validation
Valid parameters
http://plenar.io/v1/api/sensor-networks/array_of_things_chicago/check?
node=0000001e0610b9e7&sensor=bmp180&feature=atmospheric_pressure
{
"message": "Your query params are good to go."
}
Invalid parameters
http://plenar.io/v1/api/sensor-networks/array_of_things_chicago/check?
node=0000&sensor=bmp181&feature=atmospherik_pressure
{
"error": {
"feature": [
"atmospherik_pressure does not exist"
],
"node": [
"0000 does not exist"
],
"sensor": [
"bmp181 does not exist"
]
},
"meta": {
"query": {
"node": "0000",
"feature": "atmospherik_pressure",
"sensor": "bmp181"
}
}
}
GET /v1/api/sensor-networks/<network>/check
While all API endpoints will inform you if your query parameters are invalid - it can be helpful to check any combination of parameters for a given network.
Common Query Syntax
Paramater Name | Required? | Description |
---|---|---|
node(s) | no | Node ids |
sensor(s) | no | Sensor names |
feature(s) | no | Feature names |
HTTP Data Queries
These endpoints let you quickly fetch sensor observations or generate aggregates over a node’s history.
– Raw Observations
GET /v1/api/sensor-networks/<network>/query
Temperature observations from HTU21D sensors on nodes 000 and 011 in the array_of_things network
Get observations.
http://plenar.io/v1/api/sensor-networks/array_of_things_chicago/query?feature=temperature&sensors=HTU21D&nodes=000,011
{
"meta": {
"query": {
"start_datetime": "2016-06-08T17:55:32.503905",
"feature": "temperature",
"limit": 1000,
"end_datetime": "2016-09-06T17:55:32.503935",
"offset": 0,
"sensors": [
"htu21d"
],
"network": "array_of_things",
"nodes": [
"000",
"011"
]
},
"message": [],
"total": 1000
},
"data": [
{
"feature": "temperature",
"node": "011",
"sensor": "htu21d",
"meta_id": 54,
"results": {
"temperature": 30.12
},
"datetime": "2016-08-25T00:54:18"
},
...
]
}
Temperature observations from the array_of_things_chicago network in December 2016 within the given geometry
http://plenar.io/v1/api/sensor-networks/array_of_things_chicago/query?feature=temperature&geom={"type":"Polygon","coordinates":[[[40.0, -90.0],[45.0,-90.0],[45.0, -85.0],[40.0, -85.0]]]}&start_datetime=2016-12-1T00:00:00.000&end_datetime=2017-1-1T00:00:00.000
{
"meta": {
"query": {
"start_datetime": "2016-12-1T00:00:00.000",
"limit": 1000,
"geom": {"type":"Polygon","coordinates":[[[40.0, -90.0],[45.0,-90.0],[45.0, -85.0],[40.0, -85.0]]]},
"end_datetime": "2017-1-1T00:00:00.000",
"offset": 0,
"network": "array_of_things"
},
"message": [],
"total": 1000
},
"data": [
{
"feature": "temperature",
"node": "029",
"sensor": "TMP112",
"meta_id": 11,
"results": {
"temperature": 17.22
},
"datetime": "2016-12-25T00:54:18"
},
...
]
}
All below freezing temperature readings from array_of_things_chicago network in the last 1 day
http://plenar.io/v1/api/sensor-networks/array_of_things_chicago/query?feature=temperature&filter={"col": "temperature", "val": "0", "op": "le"}
{
"meta": {
"query": {
"start_datetime": "2016-12-1T00:00:00.000",
"limit": 1000,
"end_datetime": "2017-1-1T00:00:00.000",
"offset": 0,
"network": "array_of_things"
},
"message": [],
"total": 1000
},
"data": [
{
"feature": "temperature",
"node": "029",
"sensor": "TMP112",
"meta_id": 11,
"results": {
"temperature": -4.01
},
"datetime": "2016-12-25T00:54:18"
},
...
]
}
You must specify one feature of interest in the query parameters. All other parameters are optional. Response limit is 1000 by default, but can be set to a maximum of 10000.
Common Query Syntax
Parameter Name | Required? | Default |
---|---|---|
feature | yes | none |
nodes | no | all nodes in network |
sensors | no | all sensors in network |
geom | no | none |
start_datetime | no | 1 day ago |
end_datetime | no | now |
filter | no | none |
limit | no | 1000 |
Filter parameter
A single condition that applies to one property can be expressed in the following syntax: {"op":"<operator>", "prop":"<property>", "val":"<target_value>"}
, where <property>
must be a property of the feature specified by
the feature
parameter.
You can use the following binary operators:
LIKE examples:
“%rat%” matches “rat poisoning” and “crater”. “jo_” matches “joe” and “job” but not “josephine”
operator | description |
---|---|
eq |
equal to (==) |
gt |
greater than (>) |
ge |
greater than or equal to (>=) |
lt |
less than (<) |
le |
less than or equal to (<=) |
ne |
not equal (!=) |
in |
within a list of provided values like 0560,0110 |
like |
Match string pattern |
ilike |
Match string pattern, case insensitive |
Responses
Attribute Name | Attribute Description |
---|---|
query | Shows values used in the query. |
message | Reports warnings (if any). |
total | Total number of records found. |
data | Contains records |
error | Contains any errors |
either the data or error field will be returned, not both
Data Format
Attribute Name | Attribute Description |
---|---|
node | ID of the node that generated the result. |
sensor | Sensor model that generated the result. |
features | Feature of interest that the result measures. |
datetime | Time at which the reading was taken |
results | JSON of the feature of interest’s properties and measured values. |
meta_id | Integer identifier for the node configuration and calibration information that generated the reading. |
– Timeseries
/v1/api/sensor-networks/<network>/aggregate?<args>
Standard deviations of gas concentrations from sensor_dev_3 on node_dev_2 for the past day
http://plenar.io/v1/api/sensor-networks/plenario_development/
aggregate?feature=gas_concentration&node=node_dev_2
&function=std&sensors=sensor_dev_3
{
"meta": {
"query": {
"node": "node_dev_2",
"function": "std",
"start_datetime": "2016-09-22T15:42:33.147232",
"agg": "hour",
"feature": [
"gas_concentration"
],
"end_datetime": "2016-09-23T15:42:33.147302",
"sensors": [
"sensor_dev_3"
],
"network": "plenario_development"
},
"message": [ ],
"total": 24
},
"data": [
{
"n2": {
"std": 0.285770076888335,
"count": 448
},
"co2": {
"std": 0.289637279773448,
"count": 448
},
"time_bucket": "2016-09-22T15:00:00"
},
...
{
"n2": {
"std": 0.281392701124023,
"count": 287
},
"co2": {
"std": 0.299980627541392,
"count": 287
},
"time_bucket": "2016-09-23T14:00:00"
}
]
}
This endpoint lets you see historical trends by aggregating individual node observations up to larger units of time. This is done by applying one of the provided aggregate functions on all observations found within a specified window of time.
Endpoint-Specific Parameters
Parameter Name | Required? | Parameter Default | Parameter Description |
---|---|---|---|
node | Yes | None | Target node |
function | Yes | None | Aggregate function to apply: see table below |
feature | Yes | None | Node feature to aggregate |
sensors | No | All sensors | Narrows features to only those on these sensors |
start_datetime | No | Yesterday’s datetime | Beginning of observation window |
end_datetime | No | Current datetime | End of observation window |
agg | No | hour | Size of time slices: one of minute, hour, day, week, month, year |
Responses
Attribute Name | Attribute Description |
---|---|
meta | Holds meta information about the query and its result |
meta.query | Query parameters used |
meta.message | Server issued information such as warnings |
meta.total | Total number of aggregate records retrieved |
data | Holds result information from a successful query |
error | Holds error information from a failed query |
Available Aggregate Functions
key | Description |
---|---|
avg | average |
std | standard deviation |
var | variance |
min | minimum |
max | maximum |
med | median |
Bulk Data Export
GET /v1/api/sensor-networks/<network>/download
Because the raw data endpoint /query is designed to respond quickly, it is limited to 10000 observations. It also only lets you query over one feature of interest.
If you want a larger dump of data, potentially over a long period of time and over many features, you can use /download to request a bulk export.
Common Query Syntax
Parameter Name | Required? | Default |
---|---|---|
features | no | all network features |
nodes | no | all nodes in network |
sensors | no | all sensors in network |
geom | no | none |
start_datetime | no | 7 days ago |
end_datetime | no | now |
Streaming Data Queries
Data Event Format
{
"type": "sensorObservations",
"attributes": {
"sensor": "hih4030",
"node": "0000001e0610ba89",
"network": "array_of_things_chicago",
"datetime": "2017-07-13 17:14:35",
"meta_id": 0,
"feature": "relative_humidity",
"properties": {
"humidity": 431
}
}
}
Plenario uses the socket.io protocol to provide near real-time streaming of sensor data. A user may open a socket and specify nodes, features of interest, and sensors they’re interested in. Plenario will push observations that satisfies their filters to their socket. If no parameters are specified, the default is to stream all data from the array_of_things network.
Any invalid parameters and other errors will be emitted as JSON internal_error
events and no connection will be created. If all parameters are valid and no errors occur, the client will begin receiving data
events from the socket.
Start a socket client that will print any
internal_error
and all temperaturedata
events from the HTU21D sensor on nodes 00A and 00BSample Node.js client using the socket.io-client module
var socket = require('socket.io-client')('http://streaming.plenar.io?' +
'network=array_of_things_chicago&' +
'features=temperature&' +
'nodes=0000001e0610ba89&' +
'sensors=HTU21D');
socket.on('data', function (data) {
console.log(data);
});
socket.on('internal_error', function (err) {
console.log(err);
});
Sample Python client using the socketIO-client package
import json
from socketIO_client import SocketIO
socketIO = SocketIO("streaming.plenar.io", params={
'network': 'array_of_things_chicago',
'features': 'temperature',
'sensors': ['HTU21D'],
'nodes': ['0000001e0610ba89']})
def on_data(data):
print(json.dumps(data))
def on_error(err):
print(json.dumps(err))
socketIO.on('data', on_data)
socketIO.on('internal_error', on_error)
socketIO.wait()
Sample Java client using the socket.io-client-java package
import io.socket.client.*;
import io.socket.emitter.*;
import org.json.JSONObject;
public class Main {
public static void main(String[] args) throws Exception {
final Socket socket = IO.socket("http://streaming.plenar.io?network=array_of_things_chicago");
socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
@Override
public void call(Object... args) {}
}).on("data", new Emitter.Listener() {
@Override
public void call(Object... args) {
JSONObject observation = (JSONObject)args[0];
System.out.println(observation);
}
}).on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {
@Override
public void call(Object... args) {}
});
socket.connect();
}
}
Common Query Syntax
Parameter Name | Required? | Default |
---|---|---|
network | yes | none |
nodes | no | all nodes in network |
sensors | no | all sensors in network |
features | no | all features reported on by network |
Weather
GET v1/api/weather-stations/
Example Query
http://plenar.io/v1/api/weather-stations/?state=IL
A list of weather stations in Illinois.
Example Response
{
"meta": {
"status": "ok",
"query": {
"state": "IL"
},
"message": ""
},
"objects": [
{
"begin": "2006-01-01",
"elevation": 178,
"country": "US",
"state": "IL",
"location": {
"type": "Point",
"coordinates": [
-88.419,
41.425
]
},
"end": "2014-03-13",
"station_name": "MORRIS MUNI J R WAS",
"call_sign": "KC09",
"wban_code": "04867"
},
...
]
}
Query weather stations from NOAA’s Quality Controlled Local Climatological Data.
Query Parameters
All query parameters are optional.
Parameter | Description |
---|---|
station_name | Name of weather station |
call_sign | Call sign of weather station |
wban_code | Weather Bureau Army Navy (WBAN) code of weather station |
begin | Date of first weather observation |
end | Date of last weather observation |
elevation | Elevation of station (in feet) |
country | Country name |
state | Two-digit state code |
location | Latitude and longitude location of weather station. Can be queried with a GeoJSON shape using location__within . |
For any given parameter above, the query can be modified with attribute operators.
Responses
See right. weather-stations
gives a list of weather stations and attributes (described above) that match the provided query parameters.
GET /v1/api/weather/daily
Example Query
http://plenar.io/v1/api/weather/daily/?wban_code=14819&date__ge=2016-06-01
All daily weather observations at Chicago’s Midway Airport (WBAN code 14819,
station_name
CHICAGO/MIDWAY) since June 1st, 2016.Example Response
{
"meta": {
"status": "ok",
"query": {
"date__ge": "2016-06-01",
"wban_code": "14819"
},
"message": "",
"total": 30
},
"objects": [
{
"observations": [
{
"max5_direction_cardinal": "VRB",
"max2_windspeed": null,
"snowfall": null,
"dewpoint_avg": null,
"date": "2016-06-30",
"temp_avg": null,
"id": 7214974,
"max2_direction_cardinal": "VRB",
"temp_max": null,
"max2_winddirection": "VRB",
"wetbulb_avg": null,
"latitude": null,
"max5_windspeed": null,
"avg_windspeed": null,
"old_station_type": null,
"max5_winddirection": "VRB",
"precip_total": null,
"resultant_winddirection": "VRB",
"departure_from_normal": null,
"sealevel_pressure": null,
"resultant_winddirection_cardinal": "VRB",
"weather_types": null,
"snowice_depth": null,
"longitude": null,
"snowice_waterequiv": null,
"resultant_windspeed": null,
"temp_min": null,
"station_pressure": null,
"wban_code": "14819"
},
...
],
"station_info": {
"begin": "1928-10-04",
"elevation": 188.4,
"country": "US",
"state": "IL",
"location": {
"type": "Point",
"coordinates": [
-87.752,
41.786
]
},
"end": "2014-03-13",
"station_name": "CHICAGO/MIDWAY",
"call_sign": "KMDW",
"wban_code": "14819"
}
}
]
}
Query daily weather observations from NOAA’s Quality Controlled Local Climatological Data.
Query Parameters
All query parameters are optional.
Parameter | Description |
---|---|
wban_code | The Weather Bureau Army Navy (WBAN) number is the unique identifier for weather stations |
date | Date of the observations in SQL date form (e.g. ‘2003-10-05’) |
temp_max | The maximum temperature for the day in Farenheit |
temp_min | The minimum temperature for the day in Farenheit |
temp_avg | The average temperature for the day in Farenheit |
departure_from_normal | The departure from the normal average temperature for the day in Fahrenheit |
dewpoint_avg | The average dewpoint, i.e. the temperature at which water vapor condenses into water at the same rate at which it evaporates (in Fahrenheit) |
wetbulb_avg | The average temperature the air would have had at 100% humidity (in Fahrenheit) |
weather_types | A multidimensional PostgreSQL array which contains values from Federal Meterological Handbook No. 1: Surface Weather Observations and Reports, in the following six-tuple: [vicinity, intensity, desc, precip, obscuration, other]. For example, in the event of an observation of a thunderstorm with heavy rain and snow with fog, one might see: [NULL, +, TS, RA, DG, NULL] .But if it were also snowing, there would be an additional six-tuple: [NULL, NULL, NULL, SN, NULL, NULL] |
snowice_depth | In inches, the current depth of snow/ice. A 'trace’ (T) is encoded as 0.005 |
snowice_waterequiv | This would be the depth of water in inches if you could melt the snowpack instantaneously |
snowfall | Snowfall in inches on this day |
precip_total | Total precipitation in inches, during the 24-hour period ending in local standard time |
station_pressure | Average pressure in inches of mercury |
sealevel_pressure | Average sea-level pressure in inches of mercury |
resultant_windspeed | The magnitude (in miles per hour) of “resultant” wind, which is obtained by converting recorded wind speeds and directions over a 24-hour period into a single vector with a single magnitude and direction |
resultant_winddirection_cardinal | The above wind direction converted to human-readable direction, e.g. N, NE, NNE, NNW |
max5_windspeed | The maximum windspeed of recorded 5-second averages (in degrees) |
max5_winddirection | The maximum windspeed of recorded 5-second averages (in degrees) |
max5_direction_cardinal | The maximum windspeed of recorded 5-second averages (in cardinal directions) |
max2_windspeed | The maximum windspeed of recorded 2-minute averages (in degrees) |
max2_winddirection | The maximum windspeed of recorded 2-minute averages (in degrees) |
max2_direction_cardinal | The maximum windspeed of recorded 2-minute averages (in cardinal directions) |
For any given parameter above, the query can be modified with attribute operators.
Responses
See right. Weather observations and attributes (described above) that match the provided query parameters. Response is limited to 500 results, which can be paginated by using the offset
parameter.
GET /v1/api/weather/hourly
Example Query
http://plenar.io/v1/api/weather/hourly/?wban_code=14819&datetime__ge=2016-06-24
All hourly weather observations at CHICAGO/MIDWAY since June 24th, 2016.
Example Response
{
"meta": {
"status": "ok",
"query": {
"datetime__ge": "2016-06-24",
"wban_code": "14819"
},
"message": "",
"total": 23
},
"objects": [
{
"observations": [
{
"wind_direction": "110",
"datetime": "2016-06-24T23:53:00",
"report_type": "AA",
"wetbulb_fahrenheit": 65,
"id": 391713839,
"station_type": 12,
"sky_condition": "CLR",
"hourly_precip": null,
"drybulb_fahrenheit": 72,
"latitude": null,
"wban_code": "14819",
"old_station_type": null,
"visibility": 10,
"wind_direction_cardinal": "ESE",
"sealevel_pressure": 30.05,
"weather_types": null,
"wind_speed": 5,
"sky_condition_top": "CLR",
"longitude": null,
"relative_humidity": 68,
"dewpoint_fahrenheit": 61,
"station_pressure": 29.41
},
...
],
"station_info": {
"begin": "1928-10-04",
"elevation": 188.4,
"country": "US",
"state": "IL",
"location": {
"type": "Point",
"coordinates": [
-87.752,
41.786
]
},
"end": "2014-03-13",
"station_name": "CHICAGO/MIDWAY",
"call_sign": "KMDW",
"wban_code": "14819"
}
}
]
}
Query hourly weather observations from NOAA\’s Quality Controlled Local Climatological Data.
Query Parameters
All query parameters are optional.
Parameter | Description |
---|---|
wban_code | The WBAN (Weather Bureau Army Navy) number is the unique identifier for weather stations |
datetime | In SQL datetime form (e.g. '2003-10-05 23:04:00’) |
old_station_type | (Valid for all dates before May 1st, 2007)
|
station_type |
|
sky_condition | Up to three strings representing up to three layers of cloud cover. Each string is one of the below abbreviations with (in the case of clouds) a three-digit height following, representing hundreds of feet.
|
sky_condition_top | This parameter represents the highest observed sky condition (in hundreds of feet), taken from sky_condition . |
visibility | Distance at which objects can be discerned, in statute miles |
weather_types | A multidimensional PostgreSQL array which contains values from Federal Meterological Handbook No. 1: Surface Weather Observations and Reports, in the following six-tuple: [vicinity, intensity, desc, precip, obscuration, other]. For example, in the event of an observation of a thunderstorm with heavy rain and snow with fog, one might see: [NULL, +, TS, RA, DG, NULL] . But if it were also snowing, there would be an additional six-tuple: [NULL, NULL, NULL, SN, NULL, NULL] |
drybulb_fahrenheit | Current temperature at current level of humidity (in Fahrenheit) |
wetbulb_fahrenheit | The temperature the air would have at 100% humidity (in Fahrenheit) |
dewpoint_fahrenheit | The temperature at which water vapor condenses into water at the same rate at which it evaporates (in Fahrenheit) |
relative_humidity | Expressed as a percentage (0 to 100), the ratio of the partial pressure of water vapor to the saturated vapor pressure at the current temperature |
wind_speed | Observed wind speed (averaged?) (in miles per hour) |
wind_direction | Observed wind direction (averaged?) in degrees (0 to 360) |
wind_direction_cardinal | Observed wind direction (averaged?) as a human-readable direction, e.g. N, NE, NNE, NNW |
station_pressure | Average pressure in inches of mercury |
sealevel_pressure | Average sea-level pressure in inches of mercury |
report_type | Standard reports are denoted 'AA’ and special reports (e.g. for tornadoes) are 'SP’.
|
hourly_precip | Precipitation total (in inches) |
For any given parameter above, the query can be modified with attribute operators.
Responses
Hourly weather observations and attributes (described above) that match the provided query parameters. Response is limited to 500 results, which can be paginated using the offset
parameter.
GET /v1/api/weather/metar
Example Query
http://plenar.io/v1/api/weather/metar/?wban_code=94846&datetime__ge=2016-06-29&datetime__le=2016-06-30
All metar weather observations at CHICAGO/MIDWAY between June 30th and July 1st, 2016.
Example Response
{
"meta": {
"status": "ok",
"query": {
"datetime__le": "2016-06-30",
"datetime__ge": "2016-06-29",
"wban_code": "94846"
},
"message": "",
"total": 24
},
"objects": [
{
"observations": [
{
"wind_direction": "90",
"datetime": "2016-06-29T23:51:00",
"precip_24hr": null,
"id": 8903473,
"sky_condition": "SCT065 BKN230",
"call_sign": "KORD",
"latitude": null,
"wban_code": "94846",
"precip_1hr": null,
"visibility": 10,
"wind_direction_cardinal": "E",
"temp_fahrenheit": 73.94,
"sealevel_pressure": 30.0437219724,
"weather_types": [ ],
"wind_speed": 12,
"wind_gust": null,
"precip_6hr": null,
"precip_3hr": null,
"sky_condition_top": "BKN230",
"longitude": null,
"dewpoint_fahrenheit": 46.94,
"station_pressure": 30.05
},
...
],
"station_info": {
"begin": "1946-10-01",
"elevation": 205.4,
"country": "US",
"state": "IL",
"location": {
"type": "Point",
"coordinates": [
-87.934,
41.995
]
},
"end": "2014-03-13",
"station_name": "CHICAGO/O HARE ARPT",
"call_sign": "KORD",
"wban_code": "94846"
}
}
]
}
Query METAR weather observations. METARs (Meterological Terminal Air Reports) are a frequently updated (every hour or more) form of surface weather data.
METAR data is only stored for recent dates (e.g. the last 2-3 days) for which there is not yet an hourly QCLCD (quality-controlled) observation. If METARs are unavailable for a range of recent dates, check the hourly weather API.
Query Parameters
All query parameters are optional
Parameter | Description |
---|---|
wban_code | The WBAN (Weather Bureau Army Navy) number is the unique identifier for weather stations |
call-sign | Call sign of weather station |
datetime | In SQL datetime form (e.g. '2003-10-05 23:04:00’) |
sky_condition | Up to three strings representing up to three layers of cloud cover. Each string is one of the below abbreviations with (in the case of clouds) a three-digit height following, representing hundreds of feet.
|
sky_condition_top | This parameter represents the highest observed sky condition (in hundreds of feet), taken from sky_condition . |
visibility | Distance at which objects can be discerned, in statute miles |
weather_types | A multidimensional PostgreSQL array which contains values from Federal Meterological Handbook No. 1: Surface Weather Observations and Reports, in the following six-tuple: [vicinity, intensity, desc, precip, obscuration, other]. For example, in the event of an observation of a thunderstorm with heavy rain and snow with fog, one might see: [NULL, +, TS, RA, DG, NULL] . But if it were also snowing, there would be an additional six-tuple: [NULL, NULL, NULL, SN, NULL, NULL] |
temp_fahrenheit | Current temperature at current level of humidity (in Fahrenheit) |
dewpoint_fahrenheit | The temperature at which water vapor condenses into water at the same rate at which it evaporates (in Fahrenheit) |
relative_humidity | Expressed as a percentage (0 to 100), the ratio of the partial pressure of water vapor to the saturated vapor pressure at the current temperature |
wind_speed | Observed wind speed (averaged?) (in miles per hour) |
wind_direction | Observed wind direction (averaged?) in degrees (0 to 360) |
wind_direction_cardinal | Observed wind direction (averaged?) as a human-readable direction, e.g. N, NE, NNE, NNW |
station_pressure | Average pressure in inches of mercury |
sealevel_pressure | Average sea-level pressure in inches of mercury |
precip_1hr | Precipitation total in the last 1 hour (in inches) |
precip_3hr | Precipitation total in the last 3 hours (in inches) |
precip_6hr | Precipitation total in the last 6 hours (in inches) |
precip_24hr | Precipitation total in the last 24 hours (in inches) |
For any given parameter above, the query can be modified with attribute operators.
Responses
Metar weather observations and attributes (described above) that match the provided query parameters. Response is limited to 500 results, which can be paginated by using the offset
parameter.
Providers
This section is specifically for those who are providers of sensor network data to Plenario. It assumes that you have received an administrative account on apiary.
About
We ensure Plenario does not ingest junk data by filtering the incoming stream. This filtering is based on metadata descriptions of sensor networks which Plenario utilizes to store and query observations in a meaningful way.
If you would rather use the browsable api, it’s still recommended to skim this section just to see an example of what valid data looks like, as well as how all the pieces fit together.
Adding a network
POST /api/networks/?format=vnd.api%2Bjson
curl "http://apiary.plenar.io/api/networks/?format=vnd.api%2Bjson" \
--user username:password \
--data "name=mysensornetwork&info={}"
Plenario first needs to know what network a node will belong to. If you intend to add nodes to an existing network, you can skip this section.
Parameter | Description |
---|---|
name | Unique name for a network |
info | Miscellaneous metadata about the network in the form of JSON |
Adding a feature
POST /api/features/?format=vnd.api%2Bjson
curl "http://apiary.plenar.io/api/features/?format=vnd.api%2Bjson" \
--user username:password \
--data 'name=sound&observed_properties=[
{"name": "intensity", "type": "double precision"},
{"name": "duration", "type": "double precision"}
]'
If any of your node’s sensors are reporting something we do not have a feature for, you can add it like this. Here we’ve created a hypothetical feature for sensors which report on ‘sound’ as 'intensity’ and 'duration’.
Parameter | Description |
---|---|
name | Unique name for a feature |
observed_properties | List of json objects containing the 'name’ and 'type’ keys |
Values for the type key must be an accepted Redshift data type.
Adding a sensor
POST /api/sensors/?format=vnd.api%2Bjson
curl "http://apiary.plenar.io/api/sensors/?format=vnd.api%2Bjson" \
--user username:password \
--data 'name=snd3000&observed_properties={
"dur": "sound.duration",
"val": "sound.intensity"
}&info={}'
This adds a sound sensor that reports values as 'dur’ and 'val’. Given that we have a sound feature that we created earlier, we go ahead and map these values to that feature. Now this sensor’s sound values can be queried alongside any other sensor that also reports sound values.
Parameter | Description |
---|---|
name | Unique name for a feature |
observed_properties | Map of reported sensor values to feature properties |
Adding a node
POST /api/nodes/?format=vnd.api%2Bjson
curl "http://apiary.plenar.io/api/nodes/?format=vnd.api%2Bjson" \
--user username:password \
--data "id=mynode2&sensor_network=plenario_development&info={}\
&sensors=snd3000&sensors=tmp112&location={\
\"type\": \"Point\",\
\"coordinates\": [-104.7858045, 39.8087029]\
}"
Finally we can register nodes. Here we’ve created a node that has both a sound and a temperature sensor.
Parameter | Description |
---|---|
id | Unique name for a feature |
sensor_network | Name of the network this node belongs to |
info | Miscellaneous information about the node |
sensors | Name of a sensor contained by this node |
location | Physical location of the node as GeoJSON or WKT |
Reporting an observation
{
"network": "mysensornetwork",
"meta_id": "version_id",
"node_id": "mynodeid",
"sensor": "snd3000",
"datetime": "2017-01-01T00:00:00",
"data": {
"dur": 3.0,
"val": 15.7
}
}
Python 3
import boto3
kinesis_client = boto3.client(
'kinesis',
aws_access_key_id=AWS_ACCESS_KEY,
aws_secret_access_key=AWS_SECRET_KEY,
region_name='us-east-1',
)
kinesis_client.put_record(**{
'StreamName': 'ObservationStream',
'PartitionKey': 'arbitrary',
'Data': json.dumps(payload)
})
With all this metadata in place, Plenario can begin to ingest data that you send to its observation stream. Observations are pushed using any of Amazon’s Kinesis client libraries. An observation represents a single report made by a sensor. They must be formatted as json, with the observation values matching the observation property map defined for that sensor.