# Time tracking using Gateway Timer Script

**URL:** <https://forum.inductiveautomation.com/t/time-tracking-using-gateway-timer-script/94076>\
**Category:** Ignition\
**Tags:** perspective\
**Created:** [August 1, 2024, 6:19pm UTC](https://forum.inductiveautomation.com/t/time-tracking-using-gateway-timer-script/94076 "2024-08-01T18:19:03Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![VerminProgrammer](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/verminprogrammer/32/65954_2.png) [@VerminProgrammer](https://forum.inductiveautomation.com/u/VerminProgrammer)\
**Post date:** [August 1, 2024, 6:19pm UTC](https://forum.inductiveautomation.com/t/time-tracking-using-gateway-timer-script/94076/1 "2024-08-01T18:19:04Z")

</div>

Hello, I am new to ignition and python as a whole and have been trying to get the following setup on a small scale first before expanding it.

I have a VFD that will send Dint to my SCADA platform that designates VFD run time. I want the SCADA to do a periodic script ~ 1 min or so to update the memory tag stored on the gateway if the VFD time is greater than the memory tag, then vice versa so that if the VFD time is lower than the gateway it will be updated to the larger time. So far I have this and haven't been able to get any updated results with just looking at the VFD run state first.

```python
# Function to update VFD run hours
def update_vfd_run_hours1():
    # Read current run state
	run_state1[0] = system.tag.readBlocking("[default]CUP/CNWR/PMP1/VFD/RunHours")
	memory_state1[0] = system.tag.readBlocking("[default]CHW/VFD/Runtime/CHP-1")

    # Compare VFD and Gateway hours and set if VFD hours are greater
    	if run_state1[0].value > memory_state1[0].value:
			memory_state1[0].value = run_state1[0].value
			system.tag.writeBlocking("[default]CHW/VFD/Runtime/CHP-1", 'memory_state1[0].value')

```

It checks out fine when I save it, but the function of the block doesn't actually do anything. I have also tried adding in a `print memory_state1[0].value` after the last line and it doesn't actually print anything.

Hopefully I am just missing something extremely obvious but I have read through the help articles many times.

---

<div class="post-metadata">

**Author:** ![Samuel\_Sueur](https://avatars.discourse-cdn.com/v4/letter/s/e36b37/32.png) [@Samuel\_Sueur](https://forum.inductiveautomation.com/u/Samuel_Sueur)\
**Post date:** [August 1, 2024, 6:33pm UTC](https://forum.inductiveautomation.com/t/time-tracking-using-gateway-timer-script/94076/2 "2024-08-01T18:33:52Z")

</div>

Hi, yes from what I can read, there is a mistake

> [@VerminProgrammer](#):
>
> `run_state1[0] = system.tag.readBlocking("[default]CUP/CNWR/PMP1/VFD/RunHours")`

This isn't correct, you should instead use:  
`run_state1 = system.tag.readBlocking("[default]CUP/CNWR/PMP1/VFD/RunHours")[0].value`

Something like this should work:

```python
def update_vfd_run_hours1():
    # Read current run state
	run_state1 = system.tag.readBlocking("[default]CUP/CNWR/PMP1/VFD/RunHours")[0].value
	memory_state1 = system.tag.readBlocking("[default]CHW/VFD/Runtime/CHP-1")[0].value

    # Compare VFD and Gateway hours and set if VFD hours are greater
    if run_state1 > memory_state1:
		system.tag.writeBlocking("[default]CHW/VFD/Runtime/CHP-1", run_state1)

```

Please know that I highly advise against doing multiple `system.tag.readBlocking`, you should read both tags in one call.

**Also, note that I only made it so that your script works. It might not have your expected behaviour. I'll let you handle potential logic flaws.**

---

<div class="post-metadata">

**Author:** ![VerminProgrammer](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/verminprogrammer/32/65954_2.png) [@VerminProgrammer](https://forum.inductiveautomation.com/u/VerminProgrammer)\
**Post date:** [August 1, 2024, 7:14pm UTC](https://forum.inductiveautomation.com/t/time-tracking-using-gateway-timer-script/94076/3 "2024-08-01T19:14:06Z")

</div>

Hmm, I took your advice and I moved around the [0] to the end _(I am still unsure of what it actually designates to be honest)_ and I still cannot get the gateway memory tag to be overwritten with the value I am trying to read. I have even shortened it down within the script console to just the barebones of:

```python
def update_vfd_run_hours1():
    # Read current run state
	run_state1 = system.tag.readBlocking("[default]CHW/VFD/New Instance/VFD1")[0].value
	#memory_state1 = system.tag.readBlocking("[default]CHW/VFD/Runtime/CHP-1")[0].value

    # Compare VFD and Gateway hours and set if VFD hours are greater
    	system.tag.writeBlocking("[default]CHW/VFD/Runtime/CHP-1", run_state1)
    	print run_state1

```

the print function doesn't show anything other than "\>\>\>" in the script console interpreter when it should be showing my _"run\_state1"_ value.

The only other thing I can think of is that the incoming data is a double, and the memory is a float but I can change that.

Edit: I just tried the following code and I still cannot print any data

```python
def update_vfd_run_hours1():
    # Read current run state
	run_state1 = system.tag.readBlocking("[default]CHW/VFD/New Instance/VFD1")[0].value
	print "result", run_state1.value

```

I am not sure what is going on here, all tags are readable and writable I just checked to be sure.

---

<div class="post-metadata">

**Author:** ![Samuel\_Sueur](https://avatars.discourse-cdn.com/v4/letter/s/e36b37/32.png) [@Samuel\_Sueur](https://forum.inductiveautomation.com/u/Samuel_Sueur)\
**Post date:** [August 1, 2024, 7:16pm UTC](https://forum.inductiveautomation.com/t/time-tracking-using-gateway-timer-script/94076/4 "2024-08-01T19:16:09Z")

</div>

> [@VerminProgrammer](#):
>
> ```python
> def update_vfd_run_hours1():
> # Read current run state
> run_state1 = system.tag.readBlocking("[default]CHW/VFD/New Instance/VFD1")[0].value
> print "result", run_state1.value
> 
> ```

No, you should just do `print(run_state1)` to print the value.

> [@VerminProgrammer](#):
>
> ```python
> def update_vfd_run_hours1():
> # Read current run state
> run_state1 = system.tag.readBlocking("[default]CHW/VFD/New Instance/VFD1")[0].value
> #memory_state1 = system.tag.readBlocking("[default]CHW/VFD/Runtime/CHP-1")[0].value
> 
> # Compare VFD and Gateway hours and set if VFD hours are greater
> system.tag.writeBlocking("[default]CHW/VFD/Runtime/CHP-1", run_state1)
> print run_state1
> 
> ```

I think this is not working because your indentation is not correct.

Also, if you are running this in the script console, make sure to **actually call your function.**

To further explain what's going on, the return value of a `system.tag.readBlocking` is a list of ~~dicts~~ `QualifiedValues`

(thanks @paul-griffith and sorry ahah).  
Each dict contains information about the tag, you have for instance `.quality` for the quality of the tag, and `.value` for the value of the tag, hence the `[0].value` .

See the last example in this manual page:

> **[system.tag.readBlocking | Ignition User Manual](https://www.docs.inductiveautomation.com/docs/8.1/appendix/scripting-functions/system-tag/system-tag-readBlocking)**
>
> Reads the value of the tags at the given paths.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [August 1, 2024, 7:31pm UTC](https://forum.inductiveautomation.com/t/time-tracking-using-gateway-timer-script/94076/5 "2024-08-01T19:31:48Z")

</div>

> [@Samuel\_Sueur](#):
>
> a list of dicts.

Not dictionaries, but `QualifiedValue` objects:

> **[Scripting Object Reference | Ignition User Manual](https://www.docs.inductiveautomation.com/docs/8.1/appendix/reference-pages/scripting-object-reference#qualifiedvalue)**
>
> This page describes several common scripting objects

But the general point is correct. The `[0]` is Python's syntax for accessing the first element of a list or other sequence, and the `.value` is Python's syntax for accessing the `value` attribute of the given object.

---

<div class="post-metadata">

**Author:** ![VerminProgrammer](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/verminprogrammer/32/65954_2.png) [@VerminProgrammer](https://forum.inductiveautomation.com/u/VerminProgrammer)\
**Post date:** [August 1, 2024, 7:35pm UTC](https://forum.inductiveautomation.com/t/time-tracking-using-gateway-timer-script/94076/6 "2024-08-01T19:35:12Z")

</div>

I ended up getting the code to work at the thought you mentioned my indentation might be wrong. I deleted the def function line and started at the top without any definitions and I am able to read and write tags without any issue. Here is what I put in the script console that worked:

```python
run_state1 = system.tag.readBlocking("[default]CHW/VFD/New Instance/VFD1")[0].value
memory_state1 = system.tag.readBlocking("[default]CHW/VFD/Runtime/CHP-1")[0].value
print "OG val", run_state1
memory_state1 = run_state1
system.tag.writeBlocking("[default]CHW/VFD/Runtime/CHP-1", memory_state1)
print "memory state" ,memory_state1

```

It returns the strings as well as the data I need. I am now confident I don't understand the definition function now haha. I suppose I should look into further. For now I should mess with reading and writing multiple tags to save on memory resources.

If you or anyone wants to chime in on definitions I am more than happy to read it through. I will probably need to know about it in the coming weeks of my programming journey.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [August 1, 2024, 7:41pm UTC](https://forum.inductiveautomation.com/t/time-tracking-using-gateway-timer-script/94076/7 "2024-08-01T19:41:34Z")

</div>

`def` is Python's keyword for defining a function.  
You write `def`, then the function's name, then a list of possible parameters the function accepts, then a colon to open a new "scope". Every line of code you write below this colon that's indented to the same level is in the same "scope" as the function, and makes up the function.

An extremely simple function could be something like this:

```python
def add(a, b):
	return a + b

```

This is _defining_ the "add" operation, as `a + b`. But it's not actually **doing** anything yet - it's just saying "this is what the function _will_ do, with the arguments I provide it".  
If you then _call_ the function (and print the result), you see something actually happen:

```python
print add(1, 2)

```

I'd highly recommend a basic /intro Python course; most of this is just the vernacular of programming, and for better or for worse you will likely have to do _some_ amount of scripting when working with Ignition.

---

<div class="post-metadata">

**Author:** ![VerminProgrammer](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/verminprogrammer/32/65954_2.png) [@VerminProgrammer](https://forum.inductiveautomation.com/u/VerminProgrammer)\
**Post date:** [August 1, 2024, 8:09pm UTC](https://forum.inductiveautomation.com/t/time-tracking-using-gateway-timer-script/94076/8 "2024-08-01T20:09:12Z")

</div>

Just when I was thinking I had it, I am set a step back. I have the same code in the script console, as well as the timer gateway script and the code does not function when I run the gateway timer but it does when I send it through the console.

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/c/3/c3a930ec81931a12df12be9f89b6ea46b2cb82af.png)

```python
run_state1 = float
memory_state1 = float

def updateVFD1(run_state1, memory_state1):
	# Read current run state
	run_state1 = system.tag.readBlocking("[default]CHW/VFD/New Instance/VFD1")[0].value
	memory_state1 = system.tag.readBlocking("[default]CHW/VFD/Runtime/CHP-1")[0].value
	print "Original value:", run_state1
	if run_state1>memory_state1:
		memory_state1 = run_state1
		system.tag.writeBlocking("[default]CHW/VFD/Runtime/CHP-1", memory_state1)
		print "updated memory state value:" ,memory_state1
	else: 
		print "not updated"

print updateVFD1(memory_state1, 0)

```

I get this error in the gateway log:

```python
Traceback (most recent call last):
  File "<TimerScript:ShaesProject/CHP Run Hours @5,000ms >", line 16, in <module>
  File "<TimerScript:ShaesProject/CHP Run Hours @5,000ms >", line 6, in updateVFD1
NameError: global name 'system' is not defined

8.1.41 (b2024052809)
Azul Systems, Inc. 17.0.10

```

but when I remove / comment out the last "print" line it goes away, and still refuses to update the value when left in the gateway.

Gateway settings are fine: Enabled = true, Fixed Delay, Shared Threading, and a 5000 millisecond delay. Very strange 😕

---

<div class="post-metadata">

**Author:** ![Samuel\_Sueur](https://avatars.discourse-cdn.com/v4/letter/s/e36b37/32.png) [@Samuel\_Sueur](https://forum.inductiveautomation.com/u/Samuel_Sueur)\
**Post date:** [August 1, 2024, 8:23pm UTC](https://forum.inductiveautomation.com/t/time-tracking-using-gateway-timer-script/94076/9 "2024-08-01T20:23:00Z")

</div>

Have a look at this thread:

> [@Global name 'system' is not defined](https://forum.inductiveautomation.com/t/global-name-system-is-not-defined/15612/7):
>
> I have the same error with the gateway event script - Tag Change below : import StringIO import csv import os import ftplib import sys import system from datetime import date from datetime import datetime from datetime import timedelta if newValue.value==0: sys.exit() today=date.today() #Récupère la date du jour au format 'aaaa-mm-jj' datejour= str(today).replace('-','') #Remplace les - par rien yesterday=date.today() - timedelta(days=1) #Récupère la date de la veille yesterday\_jour=str(yest…

TL;DR: Add `import system` at the beginning of your updateVFD1 function

**EDIT:** I was mostly trying to fix your immediate issue but please you should definitely follow everything Paul said below.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [August 1, 2024, 8:30pm UTC](https://forum.inductiveautomation.com/t/time-tracking-using-gateway-timer-script/94076/10 "2024-08-01T20:30:28Z")

</div>

The reason for that is complicated and hard to explain - basically, legacy code baggage. The easiest fix (and a good practice overall) is to move the function you're defining into the project library. That is, literally take the whole block of code you have starting from `def` and put it into a new project library script. Name it whatever you want, and then call it from your timer script using `yourScriptLibraryName.updateVFD1()`.

That aside, you've got some syntax issues/misunderstandings that I'll correct here, but I'll again recommend a basic Python course.

```python
run_state1 = float
memory_state1 = float

```

Python doesn't require you to initialize variables before you use them, with or without type information. You can just declare a variable with a value, and the type is implicit. Drop these lines completely.

```python
def updateVFD1(run_state1, memory_state1):

```

You only need to write `run_state1`, `memory_state1` (or anything else) at the top of your function _if it's a parameter your function expects_.  
That is, look at these different function definitions:

```python
def addTwo(a):
	return a + 2

def multiplyAndAddSomething(a, b):
	something = 13
	return (a * b) + something

def doSomething():
	print "I did something!"

```

You don't need to (and shouldn't) define a method as accepting parameters if it doesn't actually need them. In your case, you're overwriting any possible input parameters _anyways_, so it's completely pointless.

> [@VerminProgrammer](#):
>
> `print "Original value:", run_state1`

`print` statements, when code is executed on the gateway, go straight to the `wrapper.log` file, which can be annoying to get to. Prefer using `system.util.getLogger` when writing gateway scripts, so you can see the output directly in the gateway webpage.  
More info here: [Event Configuration Print Out to debug - #5 by PGriffith](https://forum.inductiveautomation.com/t/event-configuration-print-out-to-debug/60091/5)

> [@VerminProgrammer](#):
>
> ```python
> memory_state1 = run_state1
> 
> ```

There's no need to reassign the value of a local variable. This won't do anything to the tags - it's just having your CPU spin for a few cycles rewriting memory with no effect.

> [@VerminProgrammer](#):
>
> `print updateVFD1(memory_state1, 0)`

As mentioned above - there's no need to pass parameters in here - just invoke the function directly (`updateVFD1()`). Also, your function isn't `return`ing anything, so there's no need to print the output - that's what the `None` value you're seeing in the script console is.

I would put the following into the project library, for now:

```python
def updateVFD1():
	log = system.util.getLogger("VFD Debug")
	run_state1 = system.tag.readBlocking("[default]CHW/VFD/New Instance/VFD1")[0].value
	memory_state1 = system.tag.readBlocking("[default]CHW/VFD/Runtime/CHP-1")[0].value

	log.info("Original value: " + run_state1)
	if run_state1 > memory_state1:
		system.tag.writeBlocking("[default]CHW/VFD/Runtime/CHP-1", memory_state1)
		log.info("Updated memory state value: " + memory_state1)
	else: 
		log.info("Not updated")

```

And then in your timer script, just write:

```python
whateverNameYouGaveYourProjectScriptLibrary.updateVFD1()

```

If you weren't aware of it, Ctrl + Space brings up the scripting autocomplete, and if you're on a recent enough version this will also bring up project library scripts.

---

<div class="post-metadata">

**Author:** ![VerminProgrammer](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/verminprogrammer/32/65954_2.png) [@VerminProgrammer](https://forum.inductiveautomation.com/u/VerminProgrammer)\
**Post date:** [August 2, 2024, 12:40pm UTC](https://forum.inductiveautomation.com/t/time-tracking-using-gateway-timer-script/94076/11 "2024-08-02T12:40:57Z")

</div>

Yes I think today should be dedicated to watching some python videos and doing some more practice before building any more scripts, I'm decent at graphics but the scripting and especially python is new to me _(you can probably see where my ancient C+ arduino coding is messing with me haha)._

I super appreciate all the help that I was given today and yesterday I did get the script to work as you said, I had to change some things around but it works just as intended and even updated it to work how I originally wanted it to. Thank you very much **Samuel\_Sueur** and especially **PGriffith** for your time with helping me 🙂

_(I can't mention you since I am new but still deserve a shoutout!)_
