Issue with gateway script writing to dataset memory tag

Hi,

We have a dataset memory tag (project tag, not client tag).
In each row of the dataset there is a date in the last column (type=date).

In some places we display the time difference of the date in one of the rows in the dataset and now - fx. “01:23:10”.

We have a gateway timer script that checks the dates in the dataset memory tag every minute.
If the date in the dataset is older than now it is overwritten with the default date 1970-01-01 00:00:00.

When the gateway timer script writes to the dataset tag it seems to work correctly.
By inspecting the data in the dataset the correct date has been written.

However the places where we display the time difference of the date in the dataset and now doesn’t work properly. They still show the difference of the date that was in the dataset before it was written to by the gateway script.

If I right click the dataset tag and restart it the problem resolves itself and the places where we display time differnece now works properly.

Does anybody know what’s wrong here?

I should mention we run Ignition v.8.0.15.

Thanks

Are the time differences calculated in the same script?

@JordanCClark
No the time difference is calculated in an expression in the component where the difference is displayed.
The expression reads the dataset tag and gets the date in a specified row and then comapres it to now.

Everything in Ignition is event driven. My guess is that your expression triggers on the selectedRow change event of the table and is ignoring the data change event.

I suggest using a propertyChange script on the power table to write to the component containing the time difference. That way, you can catch as many table events as you need.

Sample code EDIT: Since you are refreshing the data every minute, you may want to consider using timedelta(minutes = x) instead of seconds.

if event.propertyName == 'data' or event.propertyName == 'selectedRow':
	from datetime import timedelta
	rowNum = event.source.selectedRow
	dateValue = event.source.data.getValueAt(rowNum, dateColumn)
	now = system.date.now()
	if system.date.isAfter(dateValue, now):
		diff = dateValue.getTime() - now.getTime()
		diffString = str(timedelta(seconds = diff / 1000))
	else:
		diffString = '00:00:00'
	event.source.getComponent('timeDiffDisplay').text = diffString

Something to play with in the Script Console. Note that timedelta will also return days, if there is a sufficient difference:

from datetime import timedelta

now = system.date.now()
t = system.date.parse('2020-09-24 00:00:00')

print ' now: ', now
print '   t: ', t

diff = t.getTime() - now.getTime()
print 'diff: ', str(timedelta(seconds = diff/1000))
print 'diff: ', str(timedelta(minutes = diff/60000))[:-3]
1 Like

@JordanCClark
The time difference is just shown in a label component where the ‘text’ property of the label uses the following pseudo expression:

if(
lookup(toDataSet({the dataset memory tag}, the lookup value, getDate(1970,0,1), the lookup col, the result col) = getDate(1970,0,1),
'',
show timedifference)

Thank you for you in-depth reply, but I’m not sure how I can change what I have now to what you are suggesting. I can’t check for property changes in an expression.

Ah, you’re reading it from a tag. Sorry I missed that.

Mocking up a dataset tag and a label, my lookup function expression works as expected, whether I modify the dataset tag directly or through a script. All tag changes trigger the expression.

If that’s the case, why not add a column to the dataset with the timedifference using the script you’re updating the dataset with?

#Assumes incoming dataset is a pyDataSet
from datetime import timedelta

diffValues = []

for row in dataset:
	dateValue = row['dateColumn']
	if system.date.isAfter(dateValue, now):
		diff = dateValue.getTime() - now.getTime()
		diffString = str(timedelta(seconds = diff / 1000))
	else:
		diffString = ''
	diffValues.append(diffString)

system.dataset.addColumn(dataset, diffValues, 'timediff', str)

system.tag.writeBlocking(['path/to/tag'], [dataset])

You can then simplify the expression to:

lookup({'path/to/tag'}, lookupValue, '', lookupColumn ,'timediff')

Are you trying to write back to a dataset tag that is being written/computed from something else? If so, don’t. Write to a new dataset tag with the modifications.

@JordanCClark
Did you also try to modify the dataset tag with a geteway timer script?
That’s where my issue seems to come from.

Yes, I did. :slight_smile: I also tried it by leaving the dataset static, and changing the text on the label. It reverted back after the next gatway script execution.

@JordanCClark
I’m trying to figure out how you can get it working and not me.
The script is getting the dataset from the tag by doing a system.tag.readBlocking() so I don’t think it’s a pyDataSet. I’m not converting it.
From what I can tell from your code you are adding a new column? Are you replacing the enitre column with the new diffValues?
I’ll try to modify what I have now to something similar to yours and see what happens.

@pturmel
I need some sort of table that I can read from and write to continuously. At the moment it’s a dataset memory tag. I guess it could be converted to a database table, but I like the dataset tag because it’s directly on our gateway. If the table was a database on a different server there would be issues when the connection is down.

So it seems that converting the dataset to a pyDataSet in my script did the trick - I have no idea why, but it works now :slight_smile: :+1:

I should probably add that I actually changed two things:
. Dataset converted to pyDataSet
. dataset.setValueAt(row,col) changed to system.dataset.setValue(dataset,row,col,value)

So my original gateway script did the following

get the dataset: dataset = system.tag.readBlocking([dataset tag])[0].value
modify the dataset: dataset.setValueAt(row,col)
write back to the dataset tag: system.tag.writeBlocking([dataset tag],[dataset])

Now it’s changed to

get the dataset: dataset = system.tag.readBlocking([dataset tag])[0].value
convert dataset to pyDataSet: dataset_py = system.dataset.toPyDataSet(dataset)
modify the dataset: system.dataset.setValue(dataset_py,row,col,value)
write back to the dataset tag: system.tag.writeBlocking([dataset tag],[dataset_py])

So if it’s the conversion to pyDataSet or the changed way to modify the dataset that made it work I don’t know.

1 Like