Languages: English简体中文繁體中文

SensorThings API - Time Travel

In Part 3 of this series, we:

  • Retrieved all of the Locations from the SensorThings server by following the @iot.nextLink links
  • Adjusted the map display to better show the available data
So far, we've only been showing the most recent Observations for the ObservedProperty of available_bikes. However, it is often important to show historical data in order to see how data changes over time. In this part, we will show you how to instruct the SensorThings server to return data filtered according to its phenomenonTime.

Filtering Observations

Previously, we had filtered the Datastreams we were receiving according to their corresponding ObservedProperty in order to retrieve available_bike data. It is also possible to $filter against a variety of other properties, including phenomenonTime for Observations.

This is the request we've previously been using, except modified to return the most recent result before the (arbitrarily chosen) date/time of February 13, 2017 at 5pm (Eastern Standard Time, or UTC-5).

GET {{staBaseUrl}}/Locations?$expand=Things/Datastreams($filter=ObservedProperty/name eq 'available_bikes'),Things/Datastreams/Observations($filter=phenomenonTime lt 2017-02-13T17:00:00-05:00;$orderby=phenomenonTime desc;$top=1)

Note that the times are expressed in ISO 8601 combined date and time extended format. While we won't go into detail about time zones and offsets , it is a good idea to be familiar with how they are expressed, and their relation to UTC time. There can be additional complications in places that observe daylight saving time.

By choosing the correct combination of $filter and $orderby parameters, you can retrieve results to suit many purposes. For example:

  • Most recent observations before a given time: $filter=phenomenonTime lt [iso8601-time] and $orderby=phenomenonTime desc
  • First observations after a given time: $filter=phenomenonTime gt [iso8601-time] and $orderby=phenomenonTime asc
  • Observations between a time period: $filter=phenomenonTime ge [iso8601-time] and phenomenonTime lt [iso8601-time]
Note that lt means less-than, gt means greater-than, and le and ge are less-than-or-equal-to and greater-than-or-equal-to respectively.

Availability During the Day

To keep things interesting, let's try to find a way to visualize the data so that:

  • it shows something meaningful
  • there is some variation over the course of the day

For any individual person, a station is useful as long as it has at least one bike available (in case the user needs a bike) and one dock available (in case the user needs to dock their bike). So, to visualize this, let's:

  • Retrieve both the available_bikes and available_docks data. This can be done by removing the $filter=ObservedProperty/name eq 'available_bikes' parameter from the request.
  • Color the markers based on which stations are "empty", that is, either has no bikes or no docks available.
See the code on SensorThings Share

Time is Flying

So let's see which bike stations are empty. This can be done by taking the following query, and changing the phenomenonTime restriction in the nested $filter query.
GET {{staBaseUrl}}/Locations?$expand=Things/Datastreams($filter=ObservedProperty/name eq 'available_bikes'),Things/Datastreams/Observations($filter=phenomenonTime lt 2017-02-13T00:00:00-05:00;$orderby=phenomenonTime desc;$top=1)
Midnight
3:00 am
6:00 am
9:00 am
Noon
3:00 pm
6:00 pm
9:00 pm

You can see that there are a greater number of empty stations during the daytime and that, overall, they tend to be located somewhat centrally. That said, we're only using one day as a data point. There's a number of potential follow-up questions, such as whether bike/dock availability is different on weekdays vs weekends, but those are left as an exercise for the reader.

That's a Wrap

In this series, we've stepped through the process of retrieving Locations and their associated Observations from a SensorThings server, and visualizing the data on a map. Of course, there are many more things that can be done with SensorThings. Hopefully this tutorial has been a good starting point for your future explorations!