This week I'm going to talk about accessing histories using oBIX. Accessing histories is quite a straight forward process in oBIX as I'm sure you'll see.
For the purposes of this demonstration, I've created a history in Niagara so it can be exposed through oBIX.
To begin with, let's open a Web Browser and log into the oBIX lobby. There you'll see a reference to the histories. If you click on that, you'll get a list of history devices. Each history device can contain many history objects. After clicking on a history device, you'll see a list of the actual histories we'll be working with...
<obj href="http://localhost/obix/histories/test/" display="javax.baja.history.BHistoryDevice">
<ref name="NumericWritable" href="NumericWritable/" is="obix:History" />
</obj>
You'll notice that each history implements the generic 'obix:History' Contract. This object represents a normalized version of a history. Click on the history and you should see something like...
<obj href="http://localhost/obix/histories/test/NumericWritable/" is="obix:History" >
<int name="count" val="500"/>
<abstime name="start" val="2007-06-25T09:51:15.062+01:00"/>
<abstime name="end" val="2007-11-19T09:01:14.062Z"/>
<op name="query" href="~historyQuery/" in="/obix/def/obix:HistoryFilter" out="/obix/def/obix:HistoryQueryOut"/>
<op name="rollup" href="~historyRollup/" in="/obix/def/obix:HistoryRollupIn" out="/obix/def/obix:HistoryRollupOut"/>
<feed name="feed" href="~historyFeed/" of="/obix/def/obix:HistoryRecord" in="/obix/def/obix:HistoryFilter"/>
<ref name="today" href="~historyQuery?start=2007-11-19T00:00:00.000Z"/>
<ref name="last24Hours" href="~historyQuery?start=2007-11-18T09:01:14.687Z"/>
<ref name="yesterday" href="~historyQuery?start=2007-11-18T00:00:00.000Z&end=2007-11-18T23:59:59.999Z"/>
<ref name="weekToDate" href="~historyQuery?start=2007-11-18T00:00:00.000Z"/>
<ref name="lastWeek" href="~historyQuery?start=2007-11-11T23:59:59.999Z&end=2007-11-17T23:59:59.999Z"/>
<ref name="last7Days" href="~historyQuery?start=2007-11-12T09:01:14.687Z"/>
<ref name="monthToDate" href="~historyQuery?start=2007-11-01T00:00:00.000Z"/>
<ref name="lastMonth" href="~historyQuery?start=2007-10-01T00:00:00.000+01:00&end=2007-10-31T23:59:59.999Z"/>
<ref name="yearToDate (limit=1000)" href="~historyQuery?start=2007-01-01T00:00:00.000Z&limit=1000"/>
<ref name="lastYear (limit=1000)" href="~historyQuery?start=2006-01-01T00:00:00.000Z&end=2006-12-31T23:59:59.999Z&limit=1000"/>
</obj>
The object looks quite big doesn't it? We'll don't worry, some extra querying capabilities have been added to make developers lives easier.
The 'count' integer refers to the number of records stored by the history. The 'start' and 'end' date times (abstime) refer to newest and oldest records in the history.
Now 99% of the time, you'll just want to query the history to get some records back. This can be achieved in a two different ways...
- The references at the bottom of the history object ('today', 'last24Hours', 'yesterday' etc.), can be used to query the history and get back records. From the Web Browser, just try clicking on these links. You'll notice that a standard HTTP GET will get back the record data.
- Or use the '~historyQuery' Operation.
The query Operation takes an object that implements the 'obix:HistoryFilter' Contract...
<obj is="obix:HistoryFilter">
<int name="limit" val="10">
<abstime name="start" val="2007-06-25T09:51:15.062Z"/>
<abstime name="end" val="2007-11-19T09:01:14.062Z"/>
<obj/>
Therefore, if you HTTP POST the above document to the query Operation URI, you'll get back a list of history records. You may be wondering at this point, 'Why should I use the query Operation when I can perform a simple HTTP GET?'. Using the query Operation is the standard oBIX Operation included in the Contract, so I advise you use this if you can. Please note, always follow the schema being specified especially for formatting the date times (refer to ISO 8601) - always remember to include seconds and the desired timezone.
Before, we dive into the history records, note the 'limit' integer that can be specified in the 'HistoryFilter'. This curbs the number of history records we get back in a single request. Therefore, if you're expecting the possibility of getting back a 'lot' history records, it would be prudent to set this to a limit (i.e. 100) and make multiple requests.
The HTTP GET method uses the same Properties (start, end and limit) except these are encoded as extra parameters in the URI. Also, the HTTP GET method is only applicable to a Niagara based oBIX Server and hence is not part of the generic oBIX standard.
Once a query has been made, the following document is given as the response...
<obj is="obix:HistoryQueryOut" >
<list name="data" of="#RecordDef obix:HistoryRecord">
<obj>
<abstime name="timestamp" val="2007-11-19T09:31:12.953Z"/>
<real name="value" val="22.217134475708008"/>
</obj>
<obj>
<abstime name="timestamp" val="2007-11-19T09:31:13.984Z"/>
<real name="value" val="31.62298583984375"/>
</obj>
</list>
<int name="count" val="2"/>
<abstime name="start" val="2007-11-19T09:31:12.953Z"/>
<abstime name="end" val="2007-11-19T09:39:42.546Z"/>
<obj href="#RecordDef" is="obix:HistoryRecord">
<abstime name="timestamp"/>
<real name="value" unit="obix:units/null"/>
</obj>
</obj>
Parsing this information should be fairly straight forward. The list contains a number of history records with a time stamp and value. After the list, the number of records and the start and end time stamp are given. As with all oBIX development, you should always be mindful of the Contract being specified. In this particular case, the Contract for 'obix:HistoryRecord' is given at the bottom of the document.
History Rollup requests can also be made using the '~historyRollup' Operation. This works in a very similar way to the '~historyQuery' Operation. A History Rollup allows the user to access the count, min, max, average and sum of a history over a given time period. The '~historyRollup' Operation takes an object that implements the 'obix:HistoryRollupIn' Contract...
<obj is="obix:HistoryRollupIn">
<reltime name="interval" val="PT1H" />
</obj>
Please note, that a 'HistoryRollupIn' is also a 'HistoryFilter'. Therefore, 'limit', 'start' and 'end' can also be used. I can invoke the Operation via an HTTP POST to the '~historyRollup' URI (the interval being used here is 1 hour).
And the response...
<obj is="obix:HistoryQueryOut">
<list name="data" of="obix:HistoryRollupRecord">
<obj>
<abstime name="start" val="2007-12-03T15:26:39.842Z"/>
<abstime name="end" val="2007-12-03T15:35:11.311Z"/>
<int name="count" val="499"/>
<real name="min" val="2.807351411320269E-4"/>
<real name="max" val="99.99894714355469"/>
<real name="avg" val="50.000332826774155"/>
<real name="sum" val="24950.166080560302"/>
</obj>
</list>
<int name="count" val="1"/>
<abstime name="start" val="2007-12-03T15:26:39.842Z"/>
<abstime name="end" val="2007-12-03T15:35:11.311Z"/>
</obj>
The 'HistoryRollupRecord' contains all the information we're interested in and can be easily parsed. For more information, please read the official oBIX document available for download here.
Finally, we have the concept of being able to 'Watch' a history. A 'Watch' is covered in an earlier part of the guide. This enables us to subscribe to a real-time feed of history records. Each time the Watch is polled, we get back the latest set of history records. More information on a 'Watch' is available in an earlier part of the guide here.
Next time I'll be discussing the oBIX Batch Operation!