Well, no. Not accurately. Tag execution intervals are approximate, and heavy load on the gateway will add to the inaccuracy.
Plus, your expression's use of itself makes a circular reference that will almost certainly choke on gateway restart.
The reliable way to have such a timer is to use a single datetime memory tag that holds the timestamp of the most recent reset.
Wherever you need to display the seconds since that timestamp, use:
dateDiff({[provider]path/to/memory/tag}, now(), 'second')
Whatever script you are using to write to your reset tag, change to simply write the current timestamp (from system.date.now()
) to the memory tag.
Precise, zero gateway workload, simple reset. Even "counts" during gateway restarts.
Edit: Hmmm. The above doesn't handle the run indicator. A more complicated solution is needed for accuracy and robustness for such:
-
A memory tag of type double to hold "Prior Runtime Seconds"
-
Two memory tags of type datetime to hold the last "On" and "Off" timestamps of the run indicator.
-
A valueChange event script on the run indicator tag to intelligently update those memory tags (presumably all in the same tag folder). Something like this:
def valueChange(....):
prior, onTS, offTS = [x.value for x in readBlocking(['[.]PriorSeconds', '[.]OnTimestamp', '[.]OffTimestamp'])]
if currentValue.value:
# Run Indicator is ON
if offTS.after(onTS):
# Really is transition to ON
system.tag.writeBlocking(['[.]OnTimestamp'], [system.date.now()])
else:
# Run Indicator is OFF
if not offTS.after(onTS):
# Really is transition to OFF
now = system.date.now()
interval = 0.001 * (now.time - onTS.time)
system.tag.writeBlocking([['[.]PriorSeconds', '[.]OffTimestamp'], [prior + interval, now])
-
Your reset operation simultaneously writes now() to the OnTimestamp and 0.0 to the PriorSeconds tags.
-
Your display expression becomes:
if(
{[provider]path/to/run/indicator},
{[provider]path/to/PriorSeconds} + dateDiff({[provider]path/to/OnTimestamp}, now(), 'second'),
{[provider]path/to/PriorSeconds}
)