From OpenOrg
Jump to: navigation, search

It is arguable that meter data isn't a good fit for RDF and SPARQL. Given a conservatively estimated hundred meters with half-hourly readings you're looking at 4800 readings a day, and at ~5 triples per reading you're at 8 million triples per year.

Compounding the problem is the difficulty of retrieving data for date ranges, as this would require custom indexing in one's query processor.


We define a meter:Meter, which is a physical metering device. In most cases we don't care or know about them.

We also have a meter:MeterPoint, which is the concept of something that kicks out readings. A meter:MeterPoint is then linked to a metering endpoint definition. Something like:

 <#meterPoint> a meter:MeterPoint ;
   meter:pertainsTo <#someBuilding> ;
   meter:measures meter-resource:electricity ;
   meter:series <#series> .
 <#series> a meter:TimeSeries ;
   meter:endpoint <#endpoint> ;
   meter:seriesName "my-meter-point" ;
   meter:quantity meter-quantity:energy-used-net .
 <#endpoint> a meter:TimeSeriesEndpoint .

Time-series API specification

Each time-series API is provided at a single URL taking the following query parameters:

  • series: A comma-separated list or '*' specifying the series for which to return data. Matches up with meter:seriesName above.
  • startTime: A YYYY-MM-DDTHH:MM:SS+ZZ:00 timestamp giving the lower bound on results.
  • endTime: Another timestamp giving the upper bound
  • startIndex: The beginning offset within the series from which to return results. Use negative indices to offset from the end of the series
  • endIndex: The end offset. You can use negative offsets here, too.
  • periodicity: A string from the set {'halfhour', 'day', 'week', 'month', 'year'}
  • limit: The maximum number of results to return per series
  • offset: The number of results to skip per series
  • format: Overrides content negotiation

startIndex and endIndex are used like Python's slice operations. offset and limit are used for pagination. Using either of startIndex and endIndex with either of startTime and endTime is not supported, and must result in a 400 error.

Endpoints may define defaults and limits on any of these values. Where possible the endpoint should cap out of range values. These may be declared when the endpoint is queried without query parameters; see below.

Results format

As a minimum you should support JSON and JSONP. You should content-negotiate on content-type.

You may also wish to support XML and RDF data cube. These serialisations haven't been fully specified, so please discuss your plans with the rest of the community.

You should serve all responses with a "Access-Control-Allow-Origin: *" header so that data can be fetched by in-browser JavaScript cross-domain.


 { '<seriesName>' : { 'limit': <limit>,
                      'offset': <offset>,
                      'data': [{'ts': <jsTimeStamp>, 'val': <value>}],
                      'periodicity': '<periodicity>',
                      'type': 'counter',


Note: This needs more work.

   <timeSeries name="seriesName" limit="10" offset="5" periodicity="halfhour" type="counter">
     <datum ts="ISO8601TimeStamp" val="123"/>

Endpoint description

When an endpoint is queried without parameters you should return something along the following lines:


 { 'meta': { 'limit': {'default': 100, 'maximum': 1000,},


  • Entire data (use pagination)
  • Data for "now" for all meters (compared with average for this time of day / day of week )
  • Show data for today/week/year
  • Various levels of granularity (day, week, month, year)