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?
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.
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
system.tag.writeBlocking(tagPaths,tagValues)
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.
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().