Read and Write Functions
Data reading and writing is a key part of Historian functionality. There are many rules and best practices and many use cases that are not all documented here. With the following documentation you will see how to write raw values and read them back as raw values and then how to instruct the Data Archiver to perform calculations on the raw samples and return the result.
The method to pass filter parameters and query modifiers is shown but not the meaning of those parameters. Store and forward buffering is available for data writes but is an advanced topic not demonstrated here.
The Read and Write functions are:
ihDataAdd
Use this function to add data to the Data Archiver:
Prototype
ihDataAdd {
ihServerHandle hServer, // server handle returned from previous call to ihServerConnect
ihUNSIGNED long NumberOfTags, // the number of data samples being written
ihString *Tagnames, // the tagname of each sample
ihDataProperties *DataValues, // the timestamp, value, and quality of each sample
ihAPIStatus *ErrorStatuses, // output parameter for per data sample errors
ihBoolean WaitForReply, // TRUE if the call should wait for success or failure from Data Archiver.
FALSE means that you do not want to do any error checking
ihBoolean ErrorOnReplace // TRUE if you want an error returned instead of overwriting data
);
Remarks
Although the parameter is called NumberOfTags it is really NumberOfSamples. Even if you are writing multiple samples to the same tagname you need to pass the tagname with each data sample. Every data sample you pass needs a tagname in the Tagnames parameter and a timestamp, value, and quality in the DataValues parameter.
The application would write data timestamps that are in GMT+0 timezone. The Data Archiver does not do any conversion. If your timestamps are in local time and the data is retrieved in other clients, the timestamps will not be adjusted to your time zone. The System API uses the ihTimeLCLPartsToUTCStructEx () function to help you convert timestamps.
Part of your application design is to bundle multiple data samples into one write. You can send one sample per call to ihDataAdd or send 100,000 samples or more. In most cases you can write data periodically to make it available to clients in bundles of 1,000 to 10,000 samples per call to ihDataAdd
Part of your application design is to determine what to consider bad or uncertain quality and what sub- quality to use. Your tags may be in a Data Archiver with many other tags from many other sources, these include tags written by collectors or Excel Import. You must be consistent with those tags so that clients need not have special logic for specific tags. For example, collectors use a quality of bad and a subquality of ihOffline to indicate that collection has stopped at this time in the real world. Consider including such a data sample and using the same quality and subquality in your program. In this way reports and trends need not know where the data came from.
The data type you write in the ihDataProperties does not need to match the data type of the tag in the Data Archiver. The Data Archiver will do the conversion prior to storing the data.
You should typically write with WaitForReply=TRUE
so that you can check for errors and implement error handling such as retries. If you have no error handling strategy or if you are relying on the store and for- ward functionality to deliver data you can write with wait = FALSE. This is a rare use case. Understand that store and forward functionality only make sure that the data reaches the Data Archiver, not that the data is stored in the Historian archive. There could be security errors or the Archiver may be out of disk space. The most reliable way to write data is to check for errors and even possibly to read back the data that was written.
If you do get a per data sample error that does not mean the whole write failed. Samples that return ihSTATUS_OK were written successfully.
If your program only writes data going forward in time, there is no risk of replacing data and you can pass either TRUE or FALSE for the ErrorOnReplace parameter. Otherwise, pass TRUE if you do not want accidental data overwrite or FALSE to intentionally overwrite existing data.
There are rules about writes having timestamps that are too old or too new and those are not all given here. But, you will receive an error if your write is rejected.
Returns
If you write with WaitForReply=FALSE then the return code will be ihSTATUS_OK. When using WaitForReply=FALSE the return value of the overall function will be ihSTATUS_OK on success and non ihSTATUS_OK on error which means you should investigate the per data sample error returned in the ErrorStatuses output parameter. Those errors include these values:
If you write with WaitForReply=FALSE then the return code will be ihSTATUS_OK. When using WaitForReply=FALSE the return value of the overall function will be ihSTATUS_OK on success and non ihSTATUS_OK on error which means you should investigate the per data sample error returned in the ErrorStatuses output parameter. Those errors include these values:
Returns Status | Message |
---|---|
ihSTATUS_OK |
The data sample was successfully written. |
ihSTATUS_API_TIMEOUT |
If the client program did not receive a return code before the timeout expired. This does not necessarily mean the write was not performed at the archiver, only that the client did not receive a response. |
ihSTATUS_NOT_CONNECTED |
If you are not currently connected to the Data Archiver. |
ihSTATUS_WRITE_IN_FUTURE |
If you specified a timestamp that was more than 15 minutes ahead of the Data Archiver PC clock. The Data Archiver will not accept writes that are too far into the future because it has no data file to hold them. |
ihSTATUS_DUPLICATE_DATA |
If you set ErrorOnReplace to TRUE and you would have overwritten data. |
ihSTATUS_WRITE_ARCH_OFFLINE |
If you wrote to a time period that has no archive. |
ihSTATUS_ARCH_READONLY |
If the archive covering the timestamp written is set to read only in the Historian Administrator |
ihSTATUS_ACCESS_DENIED |
If you are not allowed to write data to this tag and timestamp. Under most conditions, writes from user programs are allowed. But if you receive this error consider the following scenarios:
|
ihSTATUS_WRITE_OUTSIDE_ACTIVE |
The timestamp on the data sample is older than the data is read only" |
ihSTATUS_INVALID_TAGNAME |
The tagname you wrote to does not exist in the Data Archiver configuration. |
ihSTATUS_FAILED |
For any other type of error. |
ihDataDelete
This function is used to delete data. By using this function you are not actually deleting the data from the Data Archiver but instead hiding it and marking it as deleted.
Prototype
ihDataDelete {
ihServerHandle hServer, // server handle returned from previous call to ihServerConnect
ihUNSIGNED long NumberOfTags, // the number of data samples included in the Tagnames and DataValues parameters
ihString *Tagnames, // the tagname of the data sample to be deleted
ihDataProperties *DataValues, // the list of data samples to be deleted
ihAPIStatus *ErrorStatuses // output parameter containing error codes for individual data samples
);
Remarks
Deleting data is not actually done and this function does not clear or reset an entire tag. The reason is that the data is only hidden and not truly deleted. If you write and delete the same time range repeatedly the Historian storage becomes very inefficient.
Use the delete function to delete individual data samples so they are not returned in raw data queries or considered in calculation modes. Delete a small range of data if you have recalculated values and want to discard the previous calculations. You do not need to delete data prior to data overwrite.
The return codes for a delete are much like the ones returned from a write. ihSTATUS_OK - the data sample was successfully deleted.
Returns
Returns Status | Message |
---|---|
ihSTATUS_OK |
The data sample was successfully deleted. |
ihSTATUS_API_TIMEOUT |
If the client program did not receive a return code before the timeout expired. This does not necessarily mean the write was not performed at the archiver, only that the client did not receive a response. |
ihSTATUS_NOT_CONNECTED |
If you are not currently connected to the Data Archiver |
ihSTATUS_WRITE_ARCH_OFFLINE |
If you wrote to a time period that has no archive. |
ihSTATUS_ACCESS_DENIED |
If you are not allowed to write data to this tag and timestamp. Under most conditions, writes from user programs are allowed. But if you receive this error consider the following scenarios:
|
ihSTATUS_WRITE_OUTSIDE_ACTIVE |
The timestamp on the data sample is older than the data is read only" |
ihSTATUS_FAILED |
For any other type of error. |
ihDataOpenRecordset
This function is used to read values for one or more tags for a single start and end time, and sampling mode.
Prototype
ihDataOpenRecordset {
ihServerHandle hServer, // server handle returned from previous call to ihServerConnect
ihDataFields *Fields, // which fields such as value and quality and comments you want returned
ihDataCriteria *Criteria, // all of the parameters for the read including the tagname and time range and
sampling mode
ihDataRecordset *DataRecordset // output parameter containing the retutned data samples or any per tag errors
);
Remarks
This function is used to read values for a single start and end time and sampling mode. This function is typ- ically used to read a single tagname. However, a wildcard can be passed or multiple individual tagnames can be passed.
The list of sampling and calculation modes, filtering parameters and query modifiers are passed to this function to indicate if you want raw samples returned or you want the Data Archiver to perform some calculation or summarization of the data and return the results. For example you can instruct the Data Archiver to perform hourly averages and return the results instead of returning the samples themselves.
All calculated values are returned as Double Float, regardless of the data type of the tag. Sampling modes such as lab or interpolated will return data in the tags current data type, even if the data type was changed over a period of time.
The start and end time that you enter are assumed to be in the GMT+0 time zone. If you need to convert local time zone timestamps to UTC use the ihTimeLCLPartsToUTCStructEx() utility function. The returned data will also be in GMT+0 timezone and you can use the ihTimeUTCStructToLCLPartsEx() function to convert to local time in preparation for trending or reporting.
The memory holding the returned data must be freed but do not free each field directly. Simply call the ihDataCloseRecordset() function.
For examples, refer to SDK Sample Programs.
Returns
Returns Status | Message |
---|---|
ihSTATUS_OK |
The data sample was successfully read. |
ihSTATUS_API_TIMEOUT |
The client program did not receive a portion of the returned values before the timeout expired. Large reads are sent back in multiple responses and the SystemAPI must receive at least a partial response before the timeout expires. For example if there is 90 second timeout configured, a read can take several minutes or more, as long as at least a part of the response is received every 90 seconds. |
ihSTATUS_NOT_CONNECTED |
If you are not currently connected to the Data Archiver |
ihSTATUS_ACCESS_DENIED |
If you are not allowed to read data:
|
ihSTATUS_WRITE_OUTSIDE_ACTIVE |
The timestamp on the data sample is older than the data is read only" |
ihSTATUS_FAILED |
For any other type of error. |
ihDataCloseRecordset
This function used to free the data recordset that was allocated inside the System API in a previous read call.
Prototype
void ihDataCloseRecordset {
ihDataRecordset *DataRecordset // the recordset to be freed. This comes from a previous call to
ihDataOpenRecordset
);
Remarks
Use this function to free the data recordset that was allocated inside the System API in a previous read calls.
Returns
Returns Status | Message |
---|---|
VOID |
Void |
ihDataClearAllFields
This function is used to clear the set of requested data fields.
void ihDataClearAllFields {
ihDataFields *Fields // structure to be cleared
);
Remarks
Use this function to clear the set of requested data fields (timestamp,value,quality and so on) in preparation for doing a read. After
clearing, you should set the fields that you want returned.
Returns
Returns Status | Message |
---|---|
VOID |
Void |
ihDataSubscribe
This function is used to subscribe or unsubscribe the data changes for a tag or tags in the Data Archiver.
Prototype
ihDataSubscribe {
ihServerHandle hServer, // server handle returned from previous call to ihServerConnect
ihChar *Tagname, // the tagname or wildcard of tagnames to subscribe
ihUNSIGNED long MinimumElapsedTime, // the fastest rate in milliseconds that you want data returned or 0 to return every data change
ihBoolean Subscribe // TRUE to setup a subscription or FALSE to stop receiving changes from an existing subscription
);
RemarksUse this function to subscribe or unsubscribe to data changes for a tag or tags in the Data Archiver. Subscriptions will be delivered within a few seconds of data change and are delivered to you as DataRecordset structures through the callback you previously registered with ihDataRegisterCallback() callback function. You must register a callback first if you want to receive changes. This ihDataSubscribe() function indicates the tags you want to monitor.
You can subscribe to one tag by passing a specific tagname or pass a * or other wildcard to get changes for multiple tags. If you need to monitor multiple individual tag names, then call ihDataSubscribe() function once for each tag.
Most applications will pass a 0 for minimum elapsed time indicating they want all data changes. But you can specify a minimum rate. However, you may not be notified of every change. As you are notified, you should receive the data, possibly queuing the data change, and return from the callback.
Subscriptions stay in place even after the connection lost to archiver. However, once you call ihServerDisconnect() all subscriptions are cleared. It is not necessary to unsubscribe before calling disconnect but it is suggested.
Returns Status | Message |
---|---|
ihSTATUS_OK |
if the data was successfully read. |
ihSTATUS_API_TIMEOUT |
if the client program did not receive a portion of the returned values before the timeout expired. Large reads are sent back in multiple responses and the SystemAPI must receive at least a partial response before the timeout expires. For example, if there is 90 second timeout configured, a read can take several minutes or more, as long as at least a part of the response is received every 90 seconds. |
ihSTATUS_NOT_CONNECTED |
if you are not currently connected to the Data Archiver. |
ihSTATUS_FAILED |
For any other type of error. |
ihDataGetCurrentValue
Use this function to get the current values of the one or more tags.
Prototype
ihDataGetCurrentValue {
ihServerHandle hServer,
ihDataFields *Fields,
unsigned long NumberOfTags,
ihChar **Tagnames,
ihDataProperties *DataValues,
ihAPIStatus *ErrorStatuses
);
Remarks
The ihDataGetCurrentValue function returns timestamp, value, quality, and comments. You can choose to return any of these values using the ihDataFields.
Values are returned based on the tag datatype. You should free the returned values using ihDataFreeCurrentValue()
function. Do not free the memory in your program.
You can have per tag errors. For example, if the tag does not exist or you are not allowed to read it.
Returns
Returns Status | Message |
---|---|
ihSTATUS_OK |
The data sample was successfully read. |
ihSTATUS_ACCESS_DENIED |
If you are not allowed to add or modify tags, or you are not a member of the ihReaders security group. |
ihSTATUS_FAILED |
If the tag does not exist. |
ihDataFreeCurrentValue
Use this function to free the memory in your program for the current value of the selected tags.
Prototype
ihDataFreeCurrentValue {
ihUNSIGNED long NumberOfRecords,
ihDataProperties *DataValues
);
Remarks
Use this function to free what is returned from ihDataGetCurrentValue() function. Do not free the memory any other way.
Returns
Returns Status | Message |
---|---|
VOID |
Void |
ihDataSubscribe
Use this function to subscribe or unsubscribe to data changes for a tag or tags in the Data Archiver. Subscriptions will be delivered within a few seconds of data change and are delivered to you as DataRecordset structures through the callback you previously registered with ihDataRegisterCallback() callback function. You must register a callback first if you want to receive changes. This ihDataSubscribe() function indicates the tags you want to monitor.
You can subscribe to one tag by passing a specific tagname or pass a * or other wildcard to get changes for multiple tags. If you need to monitor multiple individual tag names, then call ihDataSubscribe() function once for each tag.
Most applications will pass a 0 for minimum elapsed time indicating they want all data changes. But you can specify a minimum rate. However, you may not be notified of every change. As you are notified, you should receive the data, possibly queuing the data change, and return from the callback.
Subscriptions stay in place even after the connection lost to archiver. However, once you call ihServer- Disconnect() all subscriptions are cleared. It is not necessary to unsubscribe before calling disconnect but it is suggested.
Returns Status | Message |
---|---|
ihSTATUS_OK |
The data sample was successfully read. |
ihSTATUS_API_TIMEOUT |
The client program did not receive a portion of the returned values before the timeout expired. Large reads are sent back in multiple responses and the SystemAPI must receive at least a partial response before the timeout expires. For example if there is 90 second timeout configured, a read can take several minutes or more, as long as at least a part of the response is received every 90 seconds. |
ihSTATUS_NOT_CONNECTED |
If you are not currently connected to the Data Archiver |
ihSTATUS_FAILED |
For any other type of error. |
ihDataOpenMultiRecordset
ihDataOpenMultiRecordset {
ihServerHandle hServer,
ihUNSIGNED long NumberOfRequests,
ihDataFields *Fields,
ihDataCriteria *Criteria,
ihDataRecordset *DataRecordset
);
Remarks
This function can be used if you need to do a single read but use different sampling or calculation modes or different start and end times. You do not need to use this function simply to read multiple tags.
After checking the return value of the API call you can check the return value of each included query.
Returns
Returns Status | Message |
---|---|
ihSTATUS_OK |
The data sample was successfully read. |
ihSTATUS_API_TIMEOUT |
The client program did not receive a portion of the returned values before the timeout expired. Large reads are sent back in multiple responses and the SystemAPI must receive at least a partial response before the timeout expires. For example if there is 90 second timeout configured, a read can take several minutes or more, as long as at least a part of the response is received every 90 seconds. |
ihSTATUS_NOT_CONNECTED |
If you are not currently connected to the Data Archiver |
ihSTATUS_ACCESS_DENIED |
If you are not allowed to read data.
|
ihSTATUS_DATA_RETRIEVAL_COUNT_EXCEEDED |
If the read exceeded the Max Query Time or Max Query Intervals configured in Historian Administrator. |
ihSTATUS_FAILED |
For any other type of error. |
ihDataCloseMultiRecordset
This function is used to free the multiple recordsets returned from a ihDataOpenMultipleRecordset()
call.
Prototype
void ihDataCloseMultiRecordset {
ihUNSIGNED long NumberOfRequests,
ihDataRecordset *DataRecordsetd
);
Remarks
Use this function to properly free the multiple recordsets that were allocated inside the System API in a previous read call.
Returns
Returns Status | Message |
---|---|
VOID |
Void |
ihArchiver options
ihArchiverFreeOption Function
Prototype
ihArchiveFreeOption{
ihChar *OptionValue // the string returned from ihArchiveGetOption()
);
Remarks
Use this function to free the memory inside the structure. Do not free the fields in your code.
Returns
Returns Status | Message |
---|---|
VOID |
Void |
ihArchiverGetOption
This function retrieves an Archiver option from the data store.
ihArchiverGetOption {
ihServerHandle hServer,// server handle returned from previous call to ihServerConnect
ihOptionEx *Option, // the option and data store name
ihChar **OptionValue // output parameter containing the option value
);
This function retrieves an Archiver option from a data store. You can indicate the data store in the ihOptionEx structure. You can pass NULL as the data store name to use the default data store.
You can get an option value to confirm it is set as requested by your application, or you can use this call to verify that a set option call was successful.
ihArchiverSetOption
This function sets an Archiver option from a data store.
ihArchiverGetStatistics
This function is used to get performance statistics from the Data Archiver.
ihArchiverGetStatistics(
ihServerHandle hServer,
ihArchiveStatistics *Statistics
);
Returns Status | Message |
---|---|
ihSTATUS_OK |
If the option was successfully read |
ihSTATUS_API_TIMEOUT |
If the option could not be read and you can try again later |
ihSTATUS_NOT_CONNECTED |
If you are not currently connected to the Data Archiver |
ihSTATUS_FAILED |
For any other type of error. |