Write to client memory tag fails in tag event, yet succeeds in client timer event

I can write to a client memory tag from a client timer script, but not from the value-changed script for a tag.

Scenario:
A fresh install of Ignition 7.9.5, with one simple project.
A client timer script executes at 2 second intervals. (Was 1 second intervals for a while.)
The timer script:
-- Increments GenericSimulator.WriteableInteger1, so I know the timer script is running.
-- Toggles GenericSimulator.WriteableBoolean1.
-- Optionally toggles client string tag Info.
The write to the Info tag always succeeds.

The value-changed script in GenericSimulator.WriteableBoolean1:
-- Toggles GenericSimulator.WriteableBoolean2, so I know the WriteableBoolean1 script is running.
-- Optionally toggles client string tag Info.
The write to the Info tag never succeeds. There is no mention of the write in the wrapper log.

It is the same line of code in the two scripts.
I use GenericSimulator.WriteableInteger2 to determine which script writes to the Info tag, so there is no contention. (I also ran the test by alternately disabling the scripts, with unconditional writes; same result.)

Why would the same line of code work in the client timer script, and fail in the tag value-changed script?

Separately, and seemingly unrelated, the wrapper log has this entry at one second intervals:
-- Created auto-backup of internal database "config.idb" in 893 ms

This is the code in the timer script:
iValue1 = system.tag.read('WriteableInteger1').value
system.tag.write('WriteableInteger1', iValue1 + 1)

iValue2 = system.tag.read('WriteableInteger2').value

if system.tag.read("WriteableBoolean1").value:
system.tag.write("WriteableBoolean1", False)
if iValue2 == 1:
system.tag.write("[Client]Status/Info", "False")
else:
system.tag.write("WriteableBoolean1", True)
if iValue2 == 1:
system.tag.write("[Client]Status/Info", "True")

This is the code in the value-changed script for GenericSimulator.WriteableBoolean1:
iValue2 = system.tag.read('WriteableInteger2').value

if currentValue.value:
	system.tag.write("WriteableBoolean2", True)
	if iValue2 == 0:
		system.tag.write("[Client]Status/Info", "True")
else:
	system.tag.write("WriteableBoolean2", False)
	if iValue2 == 0:
		system.tag.write("[Client]Status/Info", "False")

Tags and tag value change scripts all live and execute in the gateway scope.

Your client tag only exists in the client, so you can only interact with it from the timer script running in the client.

Interesting.
I’ll need to adjust my thinking about the interaction between tags and project.
First thought is to use gateway scoped memory tags.
I see that gateway tags are shared among all clients.
For tags that I want to protect, can I use roles restrict access to a certain project? (A mostly rhetorical question at this point; I haven’t read that section in the manual yet.)

Surprisingly, I have the same problem with an INSERT into my database. The prepared statement method works in the client timer script, but not in the OPC tag value-changed script. Surprising because the database connection is in the gateway.

(Thanks for answering on the weekend.)

Tag events, as part of a tag, do not belong to any project, and so have no "default database". All database operations in a global gateway context must specify which database connection to use.
There are three contexts that a programmer must consider when using Ignition:

  1. Client/designer context. Client tags, global jython variables, windows, and component all exist independently in each client. Gateway tags can trigger project-specific client events, which can use both project.* and shared.* scripts. Database operations use the project's default connection if none specified, and gateway tag operations use the project's default provider.
  2. Gateway project context. Project-specific gateway events and transaction groups exist here. Client tags, windows, and components do not exist. Tag change scripts and other events in this context can use both project.* and shared.* scripts. Database operations in these scripts use the project's default connection if none specified, and gateway tag operations use the project's default provider.
  3. Gateway global aka shared context. Tag events exist here. Client tags, windows, and components do not exist. Only shared.* scripts are accessible. All database operations must specify a connection. All other tag operations must specify a provider.

Adding the database connection name solved the problem.
Thanks.
I get the general idea of the three contexts. I’ll study the manual and try more test code, especially with regard to the relationship between gateway tag events and project scripts.

There's something important missing about this description of contexts: how does a programmer create a Script(jython)/Expression(Ignition)/Database Query that is aware of its context, and how to access some object from a mismatched context when it is necessary?

1 Like

Do you mean from the designer, or within the java SDK?

You cannot. You must use messages. In part, for some contexts, because the contexts aren't even in the same computer as each other.

I mean that the Ignition Expression Language can call a Jython script from any of the three contexts using the runScript Expression. And, depending on the context (e.g. Perspective Property update vs Tag Event Scripts vs (... our company doesn't use Vision Clients, so that context only matters in the Designer), many resources (such as the Project Library of scripts) may be unavailable.

This makes calling a script from the project's Project Library when a Gateway-scope tag triggers a Tag Event Script quite difficult, unless I literally just copy-paste the code from the project's Project Library to the Gateway Scripting Project, which introduces the problem of multiple copies of the code that all need to be updated every time I save.

I guess that means that Perspective Property Binding expressions can't use a Jython method object or Jython socket object created on the Gateway global shared context even though they are running on the same device?

Is this the right page of the manual to describe messages? Component Message Handlers - Ignition User Manual 8.1 - Ignition Documentation

I'm trying to create a locking tag... I forgot what I was doing.

Maybe if I explain the whole problem here it will make sense:
There's about a dozen programmable controllers connected on the local network, controlling ovens.
It's OK for a project perspective session or a tag to query a controller and ask it for information (takes about 3 ms), but it's not OK to tell them to load instructions at the same time.

I tried to use a tag to specify which Socket is allowed to load, but when I try to make the Tag Event gray out a button on the Perspective Sessions, I run in to the problem of the script running on the wrong context.

Sounds like you need to write a driver.

Mainly because you need locking. But jython-based locking in Ignition is extremely difficult to implement correctly, because the jython life cycle for Ignition is based on projects--project saves due to designer edits throw away your code and any locks and sockets you might have created. But if you have threads running with those existing code modules and objects, they'll continue living in parallel until the thread exits.

See this recent topic and all its linked discussions:

TL/DR: Don't use sockets in anything but gateway (not Perspective) scope, and just open/write/read/close in a single operation unless you follow all the "rules" for long-lived threads and objects.

1 Like

I don't really understand what you're trying to do, but picking out this part alone, this is the wrong way to go about this. Tag event scripts should never try to directly manipulate clients; they should instead indirectly manipulate them by for example writing to other tags which the clients bind to, or write to SQL database tables, etc. I.e. affect things that are global. The client should then bind to these things and then do what they need to with that.

4 Likes

I have this exact same problem. I am trying to migrate a project from ignition 7.9 to 8.1 and a very simple tag change script, one that is basically a caller that passes an unqualified string from the tag into a project script, doesn't work in 8.1 due to scoping. How do I tell the tag change script where to look now that 'shared' doesn't exist anymore? I think I just need a location reference to hand to the python 'import' function but right clicking the script i need to import doesn't give me a usable location string... I just want to trigger a script on value change how do I do that? I don't want to move all project scripts to gateway events I want all scoping to be global or be given a way to specify the project so I can do normal project like things that work in 7.9. please help.

1 Like

How, send working example please.

I need to learn how to reference the project from the tag change script, you say it's possible, please advise.

You just call them, since the tag change scripts are created within the project they already know what project they are associated to. They will have access to any script libraries that are available within the project, inherited or otherwise.

If you have created a script library called myFuncs in your project then you can call the test() function inside of that library simply.

myFuncs.test()

What was once the Shared scripts is wrapped into a project named 'global' and a script package named 'shared' and that project is set as the Gateway Scripting Project, and any other projects are set to inherit from that project.

If you are doing this migration manually, you may want to consider creating a project to hold any "Global" scripts and then inherit from that project.

I think you are confusing the two different kinds of tag listeners.

  • Tag valueChange() events are defined on the tag. These exist in gateway global scope, and can only call scripts that are exposed through the gateway scripting project. In v7.9, these would be the scripts under shared.*. An upgrade from v7.9 will set up v8+'s more capable hierarchy so these still work.

  • Gateway Tag Change Events are defined in a project, under the scripting section of the designer tree (similar to, but separate from, Vision Client Event scripts). These are configured with a list of tags to monitor, and run a single script for any change to any of those tags. This kind of event script, because it is within a project, has access to the project's script library, and not the scripts offered by the gateway scripting project. (Unless they have overlapping inheritance, which would be true after an upgrade from v7.9)

Consider re-reading the upgrade guide with the above in mind.

For the next guy

The answer that I needed was almost in this manual section:
https://docs.inductiveautomation.com/display/DOC80/Project+Library#ProjectLibrary-GatewayScriptingProject

What it fails to do is tell you where in gateway settings exactly. So here:

This got me past my simple problem. I had embeded the tag change script in a UDT so IDK if the Gateway Tag Change Events would have worked but that would probably be cleaner

If you are upgrading from v7.9, restoring a v7.9 gateway backup as your starting point would have avoided this grief, as the gateway scripting project would have been set for you, along with the project inheritance to mimic v7.9's behavior.

Also, please point at current documentation. v8.0 has been end-of-life for years and its docs are getting stale.

...

Look I got to that answer after following your link on my actual question:

Why did I come to this thread on tangentially related problem, probably self haltered /sigh.

That 8 and 8.1 are materially different is a very, let's just say, Rockwell-like-move! /rage

Here is the closest link to what people will need in the 8.1 doc's:
https://docs.inductiveautomation.com/display/DOC81/Project+Library
scroll to bottom of page get same incomplete instruction from 8.0 doc's and then use the screen shot from my gateway to actually find what you want.

I'm just trying to help the next guy not start a flame war, but I've probably failed at both of those things...

"Computers are a sickness I am the cure." James Mickens

1 Like

Heh. We have pretty thick skins around here. (Well, most of us.) Sorry about the old topic link--v8.1 didn't exist in 2019.

Do you mean to say you don't actively update all of the links in your old posts?? :open_mouth:

1 Like