History

Overview

Refer to the javax.baja.history API.

The History module manages the storage, collection, and archiving of data logs (historical data). A data log in Niagara is often referred to as a Baja history (or history for short) and is an implementation of BIHistory. Within Niagara, histories can be accessed locally or remotely (via Niagara’s Fox communication). The History API provides the basis for creating, configuring, modifying, accessing, and deleting histories. The Driver History API provides the means for archiving histories (pulling/pushing histories from one station to another).

In order to provide support for a database of histories in a Niagara station, the History Service must be added (BHistoryService). It is responsible for creating the database and enables collection and storage of histories in the database. Once the History Service is in place, the basis for managing access to histories in the database is through the History Space (BHistorySpace). Whenever you wish to gain access to a history, it is handled by resolving through the BHistorySpace. BHistoryDatabase is a local implementation of BHistorySpace. It handles opening and closing history files as they are needed and also provides efficient access to these files.

Access

As mentioned, in order to access histories in the database, you must first gain access to the database itself. This is done by resolving the history ord scheme (as defined by BHistoryScheme). The unique history scheme name is “history”. Refer to the Naming documentation for details on Niagara’s naming system. For example, if you want to access a history named “TestLog” in a station’s database (the station being named “demo”), your ord would contain the query, “history:/demo/TestLog”. You will notice that histories are organized by their source station (device), or BHistoryDevice.

When a history is retrieved from the database, it is always an implementation of BIHistory. BIHistory is used with a HistorySpaceConnection to provide access to the following:

A history contains records which are keyed by timestamp. A record is an instance of BHistoryRecord which supplies the timestamp key (records can always be identified by timestamp) and implements the BIHistoryRecordSet interface (always a set of 1 for a single history record). A BTrendRecord is a special extension of a BHistoryRecord which adds two more tidbits of information to a history record: trend flags (BTrendFlags) and status (BStatus). Trend flags are used to provide extra context information about the record data, such as the starting record, out of order records, hidden records, modified records, or interpolated records. The status (“ok”, “alarm”, “fault”, etc.) is associated with the collected data value. The standard Niagara data value types are supported via extensions of BTrendRecord: BBooleanTrendRecord, BEnumTrendRecord, BNumericTrendRecord, and BStringTrendRecord.

Note: When a BIHistory is scanned or queried for its data records, it most often returns a Cursor (HistoryCursor) or a BITable. When iterating through this Cursor or BITable, it is important to note that it returns the same instance of BHistoryRecord for each iteration. This is done for performance reasons. So, if you need to store the records for later use as you iterate through them, be sure to make a copy of the instance (you can use the newCopy() method).

You can also query the database via a history ordQuery as defined in HistoryQuery. This allows you to find histories and filter the data returned.

Configuration and Collection

When a user is ready to start logging data in Niagara, the most common way accomplish this is by adding a concrete instance of a history extension (BHistoryExt) to a control point. This is just like adding any point extension (BPointExtension) to a control point, extending its behavior. BHistoryExt is an extension of BPointExtension, however it also implements the BIHistorySource interface which allows it to be the creator of a history. BHistoryExt is an abstract class which provides the following among other things:

There are two main types of BHistoryExts supported in the History module. These are the typed instances of BCovHistoryExt and BIntervalHistoryExt. BCovHistoryExt provides support for collecting history records triggered on changes to the value of the parent control point while BIntervalHistoryExt provides support for collecting history records based on a user defined fixed interval.

Compatibility

It is important to remember that there are two types of changes that an end user can make to a history extension (or BIHistorySource) to cause its history to be split (recreated with a new name). If the record type changes (i.e. a switch from numeric records to String records), this is an incompatible change. Another incompatible change is if the interval of collection changes. In both of these cases, the generated history will be split; the old history will keep its name, and the new history will have the same root name, but with a postfix (“_cfg#”) appended to the end of it. For example, if the history “TestLog” encounters an incompatible change, the old history will keep its records and the name “TestLog”, while any new records will be placed in a new history named “TestLog_cfg0”. If yet another incompatible change occurs after the first, the next split will have the new history named “TestLog_cfg1”, and so on.

Archiving

Refer to the Driver History documentation.

History Exceptions

The History API defines a few standard history exceptions. These all extend from HistoryException which is a BajaRuntimeException.

Changes From Niagara AX

In Niagara 4, the History API was re-factored to better support pluggable persistent storage. This allows for better scaling of the Niagara History Service since the JACE and the Supervisor are able to have different backing databases. The new API is connection oriented in order to better support the use to RDMS back-ends.

javax.baja.history.BIHistory

The following methods have been moved to javax.baja.history.HistorySpaceConneciton and take a BIHistory as a parameter.

BHistorySummary getSummary()
int getRecordCount()
BAbsTime getFirstTimestamp()
BAbsTime getLastTimestamp()
BHistoryRecord getLastRecord()
void append(BIHistoryRecordSet)
void update(BHistoryRecord)
Cursor scan()
Cursor scan(boolean)
BITable timeQuery(BAbsTime, BAbsTime)
BITable timeQuery(BAbsTime, BAbsTime, boolean)
void flush()

javax.baja.history.BHistorySpace

The following methods have been moved to javax.baja.history.HistorySpaceConneciton

boolean exists(BHistoryId)
void createHistory(BHistoryConfig)
void deleteHistory(BHistoryId)
void deleteHistories(BOrd[])
renameHistory(BHistoryId, String) 
void clearAllRecords(BHistoryId, Context)
void clearAllRecords(BOrd[], Context)
void clearOldRecords(BHistoryId, Context)
void clearOldRecords(BOrd[], Context)
The following method was added to provide access to the HistorySpace
HistorySpaceConnection getConnection(Context)

javax.baja.history.db.BHistoryDatabase

In addition to the methods from BHistorySpace, the following methods have been moved to javax.baja.history.db.HistoryDatabaseConnection

void doDeleteHistory(BHistoryId)  
void doRenameHistory(BHistoryId, String)  
void doCreateHistory(BHistoryConfig)  
void recreateHistory(BHistoryConfig, boolean)  
void resizeHistory(BHistoryId, BCapacity, BFullPolicy)  
void reconfigureHistory(BHistoryConfig)  

The following method was added to provide access to the HistoryDatabase

HistoryDatabaseConnection getDbConnection(Context)  

javax.baja.history.HistorySpaceConnection

The HistorySpaceConnection interface is AutoCloseable. It provides access to the HistorySpace and allows management of connection boundaries. Histories are obtained, queried and updated via the HistorySpaceConnection.

javax.baja.history.db.HistoryDatabaseConnection

HistoryDatabaseConnection implements HistorySpaceConnection and provides additional methods and implementations for working with BHistoryDatabases.

Code Examples

The following code examples highlight some of the History API changes between Niagara 4 and Niagara AX.

Add Records

Niagara AX

BIHistory history = db.getHistory(historyId);
for (int i=0; i<records.length; i++)
{
  history.append(records[i]);
}

Niagara 4

try (HistoryDatabaseConnection conn = db.getConnection(cx))
{
  BIHistory history = conn.getHistory(historyId);
  for (int i=0; i<records.length; i++)
  {
    conn.append(history, records[i]);
  }
}

History Query

Niagara AX

BIHistory history = db.getHistory(id);
 
BAbsTime startTime= history.getFirstTimestamp();
BAbsTime endTime = BAbsTime.make(2014, BMonth.JANUARY, 1);
 
BITable collection = history.timeQuery(startTime, endTime);
if (collection != null)
{
  Cursor cursor = collection.cursor()
  while (cursor.next())
  {
    BObject rec = cursor.get();
    if (rec instanceof BNumericTrendRecord)
    {
      displayRecord(rec);
    }
  }
}

Niagara 4

try (HistorySpaceConnection conn = db.getConnection(cx))
{
  BIHistory history = conn.getHistory(id);
 
  BAbsTime startTime = conn.getFirstTimestamp(history);
  BAbsTime endTime = BAbsTime.make(2014, BMonth.JANUARY, 1);
 
  BITable<BHistoryRecord> collection = conn.timeQuery(history, startTime, endTime);
  if (collection != null)
  {
    try(Cursor<BHistoryRecord> cursor = collection.cursor())
    {
      while (cursor.next())
      {
        BHistoryRecord rec = cursor.get();
        if (rec instanceof BNumericTrendRecord)
        {
          displayRecord(rec);
        }
      }
    }
  }
}

History Maintenance

Niagara AX

BHistoryConfig updatedConfig = makeNewConfig();
        
// Update History Configs in target history
if(db.getHistory(oldConfig.getId()) == null)
{
  db.createHistory(updatedConfig);
}
else
{
  db.reconfigureHistory(updatedConfig);
}

Niagara 4

BHistoryConfig updatedConfig = makeNewConfig();
       
try (HistoryDatabaseConnection conn = db.getDbConnection(null))
{
  // Update History Configs in target history
  if(conn.getHistory(oldConfig.getId()) == null)
  {
    conn.createHistory(updatedConfig);
  }
  else
  {
    conn.reconfigureHistory(updatedConfig);
  }
}