Tag Event Script - Determine if change originated in Ignition or PLC?

Hey folks,

Looking at adding some tag scripting on value change, and would like to separate my scripted actions based on whether the change originated in the PLC or Ignition. Is there any way to identify if the updated value originated as a write from Ignition or a read from the PLC?

Thanks in advance.

No, a value change knows nothing about the source of the change (OPC or system.tag.write*).

What are you really trying to accomplish? What is the need for knowing the origin of the change?

Good question.

A customer is experiencing some irregular behavior with in a well established system with both Ignition and HMI control. Modifying the program is not an option (OEM warranty). The Ignition interface has some audit log functionality we put together and I would like to capture changes that originated in the PLC / HMI and log it to the same dataset.

I realize I can put together tag scripting that will fire an event on any change, but it will have both Ignition and HMI sourced changes, meaning entries from Ignition will be duplicates. Not a huge issue, other than having event scripting log only PLC sourced changes would clean the data up significantly.

Does that answer your question?

Well anything you do on ignition should be seen in the audit log.

Maybe you check if value changed but no record in audit log. Though im not sure how doable it is.

How are the changes in Ignition made? Are they all scripted system.tag.write* changes or are their bindings to these tags?

It sounds like you potentially have a race condition on you're hands, where you are potentially writing to a value from two sources. Don't do that.

Something needs to be the source of truth and everything that needs to change that value should go through that source.


You're correct, if the change didn't originate from Ignition, it shouldn't be present in the audit log. I'm just looking to log those changes as well rather than comparing the audit log to the tag's history.

The changes are all being made via scripted writes, and the tags being written to are common between the HMI and Ignition. There's no race condition, just looking to expand the change tracking to include changes from outside of Ignition.

Consider adding a project script to wrap the system.tag.write* calls and then you can do any logging that you want from there. Any place that you write a tag, call your project script instead.

def writeBlocking(tagPaths,tagValues):
    #do any logging or other tasks

Thanks for the suggestion. As it stands the interface is rather minimal and all writes are contained to 4 buttons. Will consider adding a project script in their stead.

I'm not sure I'm following though; how would this lend itself to capturing changes that originate outside of Ignition?

There, is no way, from Ignition to detect the source of a change that occurred from outside of Ignition. I assume that the HMI, is modifying PLC values and that Ignition is picking up that change through the OPC subscription. To Ignition, that change looks exactly the same as a PLC change. Without, being able to change the PLC, and short of WebDev or some Thrid Party OPC Server, there isn't really a good way for the HMI to send the request through Ignition.

Unless there happens to be buffer tags between the HMI and the PLC that are only changed from the HMI. You're only option is to monitor what changes come from Ignition, any that don't are either the PLC or the HMI. If the audit log suffices for this, then great. If you require additional logging outside of the audit log, then a wrapper function is the best way to accomplish that.

There, is no way, from Ignition to detect the source of a change that occurred from outside of Ignition.

Understood. You made that pretty clear in your first reply, and I am operating with those constraints in mind.

My last comment was trying to determine what issue you were targeting with your recommendation to move to a project script. Is there some other problem you see that I've not identified, or are you just offering best practice advice?

Best practice advice. In the event that you want additional logging, outside of the audit log, then best practice is to use a wrapper in a project script.

Gotcha. Thanks for taking the time :+1:

I use a variation of this for tag writes, to make logging more consistent:

def write(paths, values, logger=None, verbose=False):
	if logger is None:
		logger = system.util.getLogger(__name__)
	l = logger.createSubLogger("TagWriteBlocking")
	if verbose:
		l.info("writing to {}: {}".format(paths, values))
	write_return = system.tag.writeBlocking(paths, values)
	bad_writes = [(path, quality) for path, quality in zip(paths, write_return) if not quality.isGood()]
	if bad_writes:
		log_msg = ' | '.join("{}: {}".format(p, q) for p, q in bad_writes)
		l.warn("bad writes: {}".format(log_msg))

It's in a script called tag, in a folder called utils, so I write tags with utils.tag.write().

1 Like