Manually storing historical data

Hi,

We have a custom Tag Provider that receives data from field devices using a custom protocol, and uses the DBTagStore API to store values. Behaves much like a driving database provider.

Our field devices now have the capability to store data during a communication link outage, and forward the saved values when the link is re-established.

This would be for tags that are already configured to store history. We want to back-fill the gaps.

This is the code I’m trying, and it’s not working. It’s inside the Tag class (SimpleTag):

[code]void addHistoricalValue(Object value, Long timestamp)
{
TagValue historyEnabled = getAttribute(TagProp.HistoryEnabled);
if ((historyEnabled != null) && historyEnabled.getValue().equals(true)) {
HistoricalTagValue histValue = new PackedHistoricalTagValue(this.getTagPath(), this.getDataType().getTypeClass(), InterpolationMode.Discrete, TimestampSource.Value, new BasicTagValue(value, DataQuality.GOOD_DATA, new Date(timestamp)));

	try {
		MyTagProvider.this.context.getHistoryManager().storeHistory(getAttribute(TagProp.PrimaryHistoryProvider).getValue().toString(), histValue);
	} catch (Exception e) {
		log.warn("Exception storing history: " + getName(), e);
	}
}

}
[/code]

The console shows the following error:

[quote]TagHistoryDatasourceSink Unknown data type received by history sink, will not be stored: class com.inductiveautomation.ignition.gateway.history.PackedHistoricalTagValue
[/quote]

I checked and the value and data type class seem OK. The value is of type Integer (Int4) and data type class accordingly.

Thanks for any support.

Ivan

Hi,

I think the only thing you need to do is wrap up the tag value in a “ScanclassHistorySet” (BasicScanclassHistorySet would be the implementation you could use). The constructor is BasicScanclassHistorySet(providerName, scanclassName, execRate). The “provider name” should be name of the realtime tag provider. The scan class name doesn’t matter, as long as the execRate=0 (which you should do). Outside that, the BasicScanclassHistorySet is just a list of HistoricalTagValues, so add your value to it.

If it makes sense, for performance reasons you might try to group multiple values together into a single history set.

Regards,

Hi Colby,

Awesome! That did the trick.

And it actually suits our system, we receive a bunch of historical values at the same time, so we can forward all of them in a single BasicScanclassHistorySet object.

Cheers,
Ivan

Hi Colby,

Just noticed something odd so I need to re-open this.

I noticed that when I send data using the code you suggested, the following happens:

  • A new row is added to sqlth_scinfo, a historical scan class named “exempt
  • When I send the historical data, the tag in sqlth_te is retired
  • A new tag is created in sqlth_te, using the scan class id for “exempt
  • Then soon after this new tag is retired, and another one is re-created using the original scan class id

I though this was caused by using an empty string for scName in BasicScanclassHistorySet(), but even if I use the same scName (and setting the same poll rate, or with poll rate = 0), it will still post the historical values under a new tagid with this exempt scan class.

Is there any way to avoid this? It would be nice to keep all historical data under the same tagid.

Cheers
Ivan

Hi,

I didn’t realize you were also storing data normally through the tag as well (I thought it was purely manual). Yes, you’ll need to make sure that the scan class, data type, and interpolation mode all match up for the tag. I suppose there could also be some issue if you’re back filling, but it should just be those three things.

Take a look at how the various rows differ. Basically, the system loads the tag id, and if it doesn’t match on those three parameters (sc, data type, and interpolation mode), it adds a new one.

Regards,

I checked those, it turned out it was the TimestampSource, tag was set up for System and I was using Value.

Now it all matches and the history is stored for the same tagid.

Cheers
Ivan

Oh, yes, of course… I forgot that “Value” timestamp source also forces it to the “exempt” scanclass.

Regards,