Languages: English简体中文繁體中文

SensorThings API - Filter Observations and Display on Chart

This is of a four-part series on representing Observations with SensorThings.

In Part 1 of this series, we saw how to display Observations of one Datastream on a chart. In Part 2, we learned how to display multiple Datastreams' Observations on a chart. In this part, we want to go a bit further and representing Observations for a particular day on a chart. We will learn how to filter Observations in SensorThings API. Also, we will learn how to move through Observations pages in case our SensorThings service supports pagination.

The only difference between this tutorial and Part 1 is in retriveing the data. So, we focus on data retrieval rather than how to show the data on the chart. You can go to Part 1 for more details on showing a dataset on the chart.

SensorThings API Filtering Capabilities

Retrieving data from SensorThings API is easy and flexible using the query options it provides. One of the useful query option for representing Observations is $filter. Basically it helps us filter our returned Observations by Observations' properties.

Lets focus on our tutorial. We want to retrieve Observations of a Datastream for a particular day. We can do it with filtering the Observations with their phenomenonTime. We will use two operators, "greater than or equal" ge / >= and "less than" lt / < as follows.

GET https://toronto-bike-snapshot.sensorup.com/v1.0/Datastreams(1504)/Observations?$filter=phenomenonTime ge '2017-02-07T00:00:00.000Z' and phenomenonTime lt '2017-02-08T00:00:00.000Z'
The code for retrieving Observations is no different from previous tutorial except in the URI to which we send HTTP GET request. Here is the code for that:
var datastreamURI = "https://toronto-bike-snapshot.sensorup.com/v1.0/Datastreams(1504)";
$.getJSON(datastreamURI , function(datastream) {
  $.getJSON(datastream["Observations@iot.navigationLink"]+"?$filter=phenomenonTime ge '2017-02-07T00:00:00.000Z' and phenomenonTime lt '2017-02-08T00:00:00.000Z'" , function(observations) {});
});

As you may noticed in HTTP GET response above, we have @iot.nextLink. SensorThings services can optionally support pagination and in that case the link to the next page of results will be in property @iot.nextLink. In this case, if we want to get all the Observations for a particular day, we need to follow through @iot.nexLink, if any. In this case, we need to make sure we retrieve all the data we need before plotting them on the chart. To this end we use JavaScript Promise to control asynchronous nature of jQuery AJAX call that we use for retrieving data.

We define a recursive function to follow through next pages until it reaches the last page (there is not @iot.nextLink available anymore). Then we convert Observations to the chart format.

Here is the code for the function:

function followNextLink(response){
  var data = [];
  // chart library expects an array of [timestamp, value]. Prepare the data returned from SensorThings for chart.
  $.map(response.value, function(observation) {
      var timestamp = moment(observation.phenomenonTime).valueOf();
      data = data.concat([[timestamp, parseFloat(observation.result)]]);
  });
  // If there is a nextLink. follow it to get all the data.
  if(response["@iot.nextLink"]!== undefined){
      return new Promise(function(resolve, reject) {
          $.getJSON(response["@iot.nextLink"], function(response){
              // Call followLink again on the response to recursively get all the data
              var resultPromise = followNextLink(response);
              resultPromise.then(function(d){
                  resolve(data.concat(d));
              });
          });
      });
  } else {
    //When there is no more next link return the data
    return Promise.resolve(data);
  }
}

Then in the call back function we call this recursive function. Here is the modified code:

var datastreamURI = "https://toronto-bike-snapshot.sensorup.com/v1.0/Datastreams(1504)";
$.getJSON(datastreamURI, function(datastream) {
  var primaryPromise = new Promise(function(resolve, reject) {
      $.getJSON(datastream["Observations@iot.navigationLink"] + "?$filter=phenomenonTime ge '2017-02-07T00:00:00.000Z' and phenomenonTime lt '2017-02-08T00:00:00.000Z'", function(response) {
          //Follow the nextLink to retrieve all the Observations for that day
          resolve(followNextLink(response));
      });
  });
  //When the whole data is ready:
  primaryPromise.then(function(data) {
      data.sort(function(a, b) {
          return a[0] - b[0];
      });

      /** Now data is ready for plotting on chart **/
  });
});

Here is the final result of plotting our data on the chart:

See the code on SensorThings Share

What's Next?

In the last tutorial of this series, we will show you how to display the latest Observation of a Datastream on a Gauge. We will learn how to retrieve that latest Observation and also about working with Gauges.

Proceed to Part 4 - Gauges