Hello, I have recently started ignition at a new job and the project I am now working on is huge. Over 50 different main screens and 20k+ tags. On one screen there is a momentary button that runs a script that is about 400 lines long. It is a mix of reading tags & OPC values, doing calculations on the values, and then writing the new values back. The script is triggered off the “mouseClicked” event handler. The problem is sometimes the values that the script is supposed to write back never get written, which then will throw an error on the screen it is located on. I am curious if I can get this button working more reliably. If it matters, the script also sets a tag value based on “mouseReleased”.
Without seeing the script I can only guess at how best to help.
First, this sounds like an Anti-pattern known as the Magic-Pushbutton. Does this type of programming, even the exact same programming, exist in other places in the project?
You should consider moving the code to a project script and generalizing it, such that it can be used in multiple places. Especially if this code is a long running task (note: not determined by the number of lines). If it is a long running task then it should be moved to a background script if it isn't already. There are numerous threads relating to that topic. Search for system.util.invokeAsynchronous().
Second group all tag reads at the start of the script and all tag writes to the end of the script. Doing single tag reads and writes will greatly increase the execution time of the script.
Finally, you said reading/writing OPC values. I would avoid reading directly from the device unless necessary, off load that work to the gateway.
Without seeing the script its going to be difficult to really help you optimize it.
This is the only button in the program that uses a script of this magnitude. It is also not something that is used anywhere other than this screen, so I do not believe it is necessary to have the script running in the background. The script is also only used every few hours at the most.
The script itself is split up. The first half of the script is reading tags and OPC values.
The second half is doing the calculating and writing. Should the calculating be split up as well? Each calculation takes place just before each write. The calculations are simple arithmetic.
value = value * value / value (example calculation)
system.tag.write(“tagpath”, value) (75x lines)
The last two lines of the script:
value = system.tag.read(“tagpath”).value
system.tag.write(“tagpath”,value)
There are over 60 lines that are reading direct OPC values, so that could definitely have an effect on the performance. I will create tags for those tomorrow and see if performance increases. If this has no effect I will upload the script. I would just like to delete the tag paths/names beforehand for privacy purposes and that may take me a bit.
Any script that needs more than one tag value or OPC item value should be using lists of tag paths or lists of item paths (with the “Blocking” function). So too with the writes–write that all at once.
I like to create a dictionary that holds all of the read values where the tagName is the key and then modify those values, then I can use that same dictionary at the end to write all of the values back.
Similar, though I’m lazy so I’ve written the scripts to account for a parent path so that I don’t have to type the entire tagPath when referencing a value.
Ah that makes a lot of sense. Will be doing this today and will report on the results when I finish. I’ve sort of inherited this project and there are definitely some rough edges so I’m just working through it piece by piece.
Got the script working. I was able to make a huge reading list and huge writing list. At the very end of the script I had to add an additional read/write because the value being read is being written in the block before it. Much better performance so far from what I can see, but I will gather more feedback as the operators use the button. Thank you for your help. I will definitely be using the readBlocking/writeBlocking for future scripts.
You really ought not to be recommending python’s datetime module. Ignition has a family of date functions for a reason. For timing measurements that aren’t affected by system clock adjustments, use java.lang.System.nanoTime(). It is monotonic and carefully synchronized across CPU cores.