Issue writing value to tag in script

I have provided a snip of the script I am attempting to write. Full disclosure, I made the move from Foxboro DCS to Ignition so there will be some syntax things I have yet to learn. In any event, the script below is tied to a pushbutton. Essentially, I want the button action to read a DINT word tag and if that value is greater than 0, set it to 0. If that tag value is 0, use the tank_sel (pulls a property value from root container) and set the dint value based on the value of the tank_sel. The data type of the root container property is a string.

The button will clear the DINT if it is > 0, however it will not write a value if the DINT is 0 at the time of the button push.

Thanks for your time!

tank_sel = event.source.parent.tank


if system.tag.readBlocking('[default]Filler_Data/DF2_SOURCE_TANK') > 0:
	system.tag.writeBlocking('[default]Filler_Data/DF2_SOURCE_TANK', 0)
elif system.tag.readBlocking('[default]Filler_Data/DF2_SOURCE_TANK') == 0:
	if tank_sel == '1':
		system.tag.writeBlocking('[default]Filler_Data/DF2_SOURCE_TANK', 1)
	elif tank_sel == '2':
		system.tag.writeBlocking('[default]Filler_Data/DF2_SOURCE_TANK', 2)
	elif tank_sel == '3':
		system.tag.writeBlocking('[default]Filler_Data/DF2_SOURCE_TANK', 4)
	elif tank_sel == '4':
		system.tag.writeBlocking('[default]Filler_Data/DF2_SOURCE_TANK', 8)

OK first things first.

Don't read and write to tags like that. Create a custom property on the rootContainer and bi-directionally bind it to your tag. Then your scripting action can be done like this (I called your custom property sourceTank):

tank_sel = event.source.parent.tank

if event.source.parent.sourceTank > 0:
	event.source.parent.sourceTank = 0
elif event.source.parent.sourceTank == 0:
	if tank_sel == '1':
		event.source.parent.sourceTank = 1
	elif tank_sel == '2':
		event.source.parent.sourceTank = 2
	elif tank_sel == '3':
		event.source.parent.sourceTank = 4
	elif tank_sel == '4':
		event.source.parent.sourceTank = 8

Try the following:

tank_sel = event.source.parent.tank                # 1
tagPath = '[default]Filler_Data/DF2_SOURCE_TANK'   # 2
sourceTank = system.tag.readBlocking([tagPath])    # 3

if sourceTank[0].value:                            # 4
    output = 0
else:
    output = 2 ** (tank_sel - 1)                   # 5

system.tag.writeBlocking([tagPath], [output])      # 6

Explanation:

  1. Original code.
  2. Readability improvement.
  3. readBlocking expects a list of tag paths. (It does work with only one value not in a list but it's not documented and could change in a future version.) readBlocking returns a list of all the "qualified values" (value, OPC quality, timestamp).
  4. Get the value (using .value) of the first (and, in this case, only) returned tag. The > 0 can be omitted because if returns True for any non-zero value.
  5. Your output value for tanks 1, 2, 3, 4 is 1, 2, 4, 8 so use the exponent to set the value in one line.
  6. As with readBlocking, writeBlocking requires lists of tag paths and values.

I think your basic problem was that you were checking the qualified tag where you needed to check .value.

See this part of the manual:

https://docs.inductiveautomation.com/display/DOC81/Reading+and+Writing+to+Tags#ReadingandWritingtoTags-ManualTagReads

1 Like

Thanks bschroeder. That works as advertised. We have quite a bit of spaghetti code thorughout the plant that is not organized as well it should be. The above example works great as I am only reading and writing the same tag (DF2_SOURCE_TK). Is it still considered general practice to create a custom property for each tag in the PLC you wish to read/write? If I were writing to 30-40 different bits in the PLC, would I address them in the script or create a property for each one and assign them bi-directionally to the PLC tag? If these tags are also accessed on a different window, that would mean creating the same number of properties on the other displays root container?

Thanks!

It really depends. As @Transistor shows, there are multiple ways to address the solution.

I typically only read/write using the system.tag functions when I'm having to dynamically build the tag path(s) required in a script. If I'm doing GUI operations, I try as hard as I can to use binding on custom properties, or indirect tag paths. However, sometimes it just makes more sense if you are doing an action and writing out to multiple tags, than writing to them via system.tag.readBlocking is the way to go.

Just realize that every system.tag.readBlocking/system.tag.writeBlocking call will block your GUI thread and can look like your client application is locked up to your user. So if you are using them, the best thing you can do is to be smart about how you are using them much like @Transistor shows. With a single read and then a single write at the end.