I am new to ignition, I have been trying to look online for a solution to a problem I am having at the moment. I have a reference tag that takes the value of another OPC tag whenever it changes, I also have a query tag (dataset) and I want to trigger the Query tag to update or refresh whenever that reference tag changes its value. I tried to use this script to read the query tag dataset and write it to a new memory tag but it doesn't work
tags = system.tag.readBlocking("path_to_querytag")
# Update the query tag value with the query result
system.tag.write("new_memory_tag_path", tags)
There's no external way to refresh a query tag other than its natural schedule, short of restarting it. (Reading a tag just gets the latest value--it has nothing to do with execution.) If the query tag is on a tag group or set to periodic, it will rerun on schedule. If set to event mode, it will rerun when some reference it is using changes. Does the reference tag participate in the query tag's SQL?
Consider not using a query tag, but dataset memory tag. Run your query via scripting when necessary, and write the result to the memory tag.
I tried that as well, but it gives me an error. I created a dataset memory tag (Writeable_M) and I run the script in the reference tag value changed .
That's my script
query = "SELECT TOP 10 * FROM test"
result = system.db.runQuery(query,"R21")
system.tag.writeBlocking("[.]Writeable_M", result)
I get that error
Error executing script.
Traceback (most recent call last):
File "<tagevent:valueChanged>", line 4, in valueChanged
at com.inductiveautomation.ignition.common.script.builtin.AbstractDBUtilities.error(AbstractDBUtilities.java:392)
at com.inductiveautomation.ignition.common.script.builtin.AbstractDBUtilities.runQuery(AbstractDBUtilities.java:359)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
java.lang.Exception: java.lang.Exception: Error executing system.db.runQuery(SELECT TOP 10 * FROM test, R21, )
When running a tag event, the script is outside any normal project scope, and therefore has no default database. The optional parameter to system.db.runQuery for the database is not optional in this situation.
Running any kind of database query, unless it always executes extremely quickly (single-digit milliseconds), is inappropriate in tag event scripts. Use a gateway tag change script instead (in the project, subscribed to the reference tag, not on the reference tag).
{ Failure to follow the fast-execution rule for tag events can crush your entire system. }
I added the following query in the gateway event script
# Update the query tag value with the query result
query = "SELECT TOP 10 * FROM test"
result = system.db.runQuery(query)
# Update the query tag value with the query result
system.tag.writeBlocking("[default]Writeable_M", result)
but when I change the value of the reference tag I added in the (tag paths) in the gateway tag change script, nothing changes in the memory dataset tag and the timestamp also doesn't change.
I also tried the gateway event script with that code
com.inductiveautomation.ignition.common.script.JythonExecException: Traceback (most recent call last): File "", line 8, in ValueError: Length of values does not match length of paths.
at org.python.core.Py.ValueError(Py.java:334)
at com.inductiveautomation.ignition.common.script.builtin.AbstractTagUtilities.writeBlocking(AbstractTagUtilities.java:542)
at jdk.internal.reflect.GeneratedMethodAccessor141.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:190)
at com.inductiveautomation.ignition.common.script.ScriptManager$ReflectedInstanceFunction.__call__(ScriptManager.java:552)
at org.python.core.PyObject.__call__(PyObject.java:477)
at org.python.core.PyObject.__call__(PyObject.java:481)
at org.python.pycode._pyx36.f$0(:8)
at org.python.pycode._pyx36.call_function()
at org.python.core.PyTableCode.call(PyTableCode.java:173)
at org.python.core.PyCode.call(PyCode.java:18)
at org.python.core.Py.runCode(Py.java:1687)
at com.inductiveautomation.ignition.common.script.ScriptManager.runCode(ScriptManager.java:803)
at com.inductiveautomation.ignition.gateway.project.ProjectScriptLifecycle$TrackingProjectScriptManager.runCode(ProjectScriptLifecycle.java:823)
at com.inductiveautomation.ignition.common.script.ScriptManager.runCode(ScriptManager.java:751)
at com.inductiveautomation.ignition.gateway.project.ProjectScriptLifecycle$TrackingProjectScriptManager.runCode(ProjectScriptLifecycle.java:804)
at com.inductiveautomation.ignition.common.script.TagChangeScriptExecutor$TagChangeExecutionCallback.execute(TagChangeScriptExecutor.java:242)
at com.inductiveautomation.ignition.common.script.TagChangeScriptExecutor$TagChangeExecutionCallback.execute(TagChangeScriptExecutor.java:194)
at com.inductiveautomation.ignition.common.util.SerialExecutionQueue$PollAndExecute.run(SerialExecutionQueue.java:102)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
at java.base/java.util.concurrent.FutureTask.run(Unknown Source)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.base/java.lang.Thread.run(Unknown Source)
Caused by: org.python.core.PyException: ValueError: Length of values does not match length of paths.
... 26 common frames omitted
Ah, you are passing a string and value to writeBlocking when it requires a list of strings and a list of values. Put square brackets around both of those to make them lists of length=one.
I was able to trigger a manual refresh by addind a custom property to the QueryTag. If you configure the tag's Execution Mode to be Event Driven, the tag's query executes when something is referenced in the code. So by referencing the custom property in the code and changing it's value from a logic of your choice, you get the desired fucntionnality.
In my case, I have a Query Tag named SomeQuery that only returns the actual Datetime. The tag has a custom property of type string named RefreshQuery. The query is event driven and references RefreshQuery. I placed a button in a Vision window or a Perspective View that writes the actual datetime to SomeQuery.RefreshQuery. When it changes, the query gets executed.
Using a string and passing the datetime at the click event, you could probably find a way to use that time to prevent the query from executing too rapidly.
On my project, on different views, and and on all open session. I send message to refresh binding to requerry (a query binding).
Instead of using query binding, I could just do a tag (with dataset type) binding? just write a new dataset to this tag and all may views and sessions will get refreshed?
I was able to use a method like this to get around the same problem.
NOTE- The tag path as of version 8.1.43 at least is [.] not [~].
Great solution for the edge cases that need this functionality. I would still like to see IA implement something better in the future so that the work around is not needed.