How to Program a Button inside a Template

Been programming in Ignition for about a year and ran into a issue I need help on.

I’ve created a PID Tuning Screen Template for an PLC application with PV, SP, & CV vertical bars, Trend Chart, Auto/Manual Indicators, and numerical inputs for the PID Gain adjustments. So far so good.

I’m using an Integer tag that contains my Loop number. So my internal tags look like - Loop X/SP, Loop X/PGain, etc.X is of course tied to a Template Parameter that I use to change Loop Numbers. All the functions listed above works fine in my application.

I need a Button inside the Template to toggle the the Auto/Manual of the Loop. I cannot identify the correct syntax to implement a Button Function inside the Template using the Component Scripting of the Button. I have been trying using the system.tag.write to do this, but again cannot implement the correct syntax for it to function. If I hard-code it to a specific Loop Number it works.

The below is one of the lines I have tried and modified different items, but to no success. I am writing a 1 or True to the tag and clearing in the PLC.

system.tag.write(‘Chiller/Loop “event.source.parent.LoopNumber”/ModePB’, 1)

Am I inside or outside the ballpark :slight_smile:

Is there a reason you don’t use a bidirectional binding with one of the various toggle buttons? Scripting is great, but binding is far easier to maintain.

I used the following code for my toggle buttons in Ignition 7.6. I had to use this method because I noticed that when I prompted for a confirmation, if the operator said no or cancel, then the toggle button would remain selected even though I had bound its selected property to a PLC tag that was very much not selected. Not sure if this was resolved in later versions or if I’m just doing it wrong, but this code definitely works (In this example, I have a custom property on a popup named OOS):


if not event.source.parent.OOS:
	if system.gui.confirm('Place Device out of Service?', 'Confirm'):
		event.source.parent.OOS = 1
	else:
		event.source.selected = 0
else:
	if system.gui.confirm('Place Device in Service?', 'Confirm'):
		event.source.parent.OOS = 0
	else:
		event.source.selected = 1

Thanks abishur and pturmel for your responses.

I am using Ignition 7.8.4 as reference.

In a Template, all of your objects have to use an Indirect Tag Bindings to pass values to the Template. AFAIK…

On all the objects that are “display” or output oriented, the “Indirect Tag Binding” dialogue is used to reference the Tag that is manipulated outside the Template, which in this case is an integer to change Loop numbers the Template is using. This works as designed and as I change the value of the tag that is referenced to PIDTUNE.LoopNumber, the template dynamically updates the internal tags inside the Template.That dialogue is shown below

Had to break into two parts…

In this Template, I also have four Input objects. Three Input text fields to enter the P,I,& D gain numbers and a PushButton to select the loop to Automatic or Manual. The Input Text Fields use the same dialogue as the output objects to enter the Indirect Tag Binding value.

But on the Pushbutton object, the regular dialogue is:

If I fill out the “Set Tag Value” Tab, which isn’t exactly like dialogue above, the auto created Script is as displayed. It looks like something I would expect, but I get errors on saving it. Errors that are indicating brackets, quotes, etc, are not in the correct place.

This follows the structure that abishur provided, but still throws an error.

Does anyone have experience programming Templates that can shed some light on what I’m doing wrong and possibly provide a working example?

What about this:

system.tag.write('Chiller/Loop' + str(event.source.parent.getComponent('LoopNumber').intValue) + '/ModePB', 1)

The way I personally like to handle this situation is to make a custom property on the template that will reference the tag. So on my template I would create the tag “AUTO” then use indirect binding to point it to the Auto tag. Make sure to select the “Bidirectional” check box in the bottom left hand corner when setting the indirect tag binding so you can write to the AUTO tag.

At this point you should be able to see the “AUTO” tag you created on the template in its “Property Editor” area. And you should be able to toggle its value AND see that written back to the PLC. If for any reason you don’t see the value in the PLC toggling then you’ve missed something in the tag binding process. As long as that custom property is configured correctly than the code I initially posted will absolutely work with no issue whatsoever.

If you aren’t concerned about confirmation prompts then it can be simplified to

if not event.source.parent.AUTO:
	event.source.parent.AUTO = 1
else:
	event.source.parent.AUTO = 0

If you want to use the system.tag.write function instead of creating custom properties with indirect tag binding then follow zxcslo’s advice it’s spot on! The way you have currently written it, Ignition is looking for a tag with the path

'Chiller/Loop "event.source.parent.LoopNumber"'/ModePB'

which doesn’t exist. using the + sign tells the scripting language (jython, a python language with the ability to use some java basically) that you’re adding parts of a string together to make a path.

My only caveat is he’s assuming that LoopNumber is a input field on the screen somewhere, if LoopNumber is a custom property then it should look something like this instead.

system.tag.write('Chiller/Loop' + str(event.source.parent.LoopNumber) + '/ModePB', 1)
2 Likes

Using the modified version of zxcslo’s solution provided by abishur works. Thank you! :relaxed:

This is what I now have in the Script for the Template Pushbutton:
system.tag.write('Chiller/Loop ’ + str(event.source.parent.LoopNumber) + ‘/ModePB’, 1)

But if you don’t mind, I would like to continue a conversation as to abishur’s comments on the Indirect Binding of the Tag I’m passing with a Template Parameter, which is “LoopNumber”.

I agree on your comments that I would prefer to bind this tag rather than use a system.write, I just cannot find where to perform the Indirect Binding on it. There is a section in the Button “Component Scripting” settings labeled “Set Tag Value” that references a type of Binding, But it’s not really Indirect Binding.

The below is what my Property Editor looks like with the tag “LoopNumber” after I have created it in the “Custom Properties” dialogue box inside the Template . It is set for a default value of 1.

At this point, I have no “Property Binding” symbol to configure this tag in the Properties Editor per your instructions in the first two paragraphs of your reply. I was expecting one, but I do not see it. So please advise if this is just a Pilot Error issue on my part and I’m missing where to access the Property Binding so I can do a Indirect Binding on this tag.

Again, this is a 7.8.4 application.

Thanks!

Template Parameters would not have a binding option, they are called “Drop targets” in the instructional videos and they are what you can pass into the template from outside of it, the data type that can be bound are the “Internal Properties”. For example, if I were to make a pump icon like this,

I would have a lot of tags associated with that pump, but I need to be able to somehow dynamically tell Ignition what data is associated with that exact pump when I place it on a screen. There are several ways to do this, but the one I decided on as a bit fit for my needs with the PLCs I am using (some Modbus based PLCs) was to create all my tags using a very structured naming scheme. Then on my template the only Template Parameter I made was one called “BaseName”

BaseName is the full tag path for the pump that all tags for that pump share. I.e. “FolderTagsAreIn/MTR03001” Then in the template I have several internal properties that will affect something on my pump like this

Each one of those properies is bound using indirect tag binding and the BaseName property like so

There are lots of other ways to do this (such as creating a User Defined Type (UDT)), but this is the way that worked best for my scenario

Thanks for your patience with me.

First time creating a Template and the videos never showed handling a Pushbutton IIRC.

The information in your last reply is exactly how I’m handling all the objects in my Template, other than I’m not passing the complete tag path, just a part of it. A picture of it is below:

All of the objects on this Template follow your example in the last image of your reply using the Indirect Tag Path and BaseName Property, again the exception being the “AUTO/MANUAL” Pushbutton. I do have the “DropTarget” selected in the configuration.

The only other Objects other than the Pushbutton that Read/Write are the PID gain value fields. These provide a Indirect Binding dialogue just like the other Objects and like you show in you last image example.

I may have been confused by some earlier comments that Indirect Binding for the Template Parameter variable on the Pushbutton could be done another way instead of the system.write method.

So I’m now just wanting to clarify is their any other and/or better way to program a Pushbutton function that needs to reference a value passed in by parameter other than using the system.write method in a Template that anyone is aware of?

There is another way.
Create a custom property (an internal property in this case) for the AUTO/MANUAL tag and use indirect tag binding on that internal property.
Then have the toggle button write to that internal property (i.e. event.source.parent.PropertyName = 1)

Now if it’s a better way is somewhat subjective. I personally find that using internal properties makes my code easier to read and I suspect, but do not know for a fact, that there might be some optimizations for using custom properties vs system.tag.write/read.

I "finally" see it now from your earlier reply - "the data type that can be bound are the "Internal Properties"

Just made the change to my project and now see the "Property Bindings" appear on my tag.

I totally agree that keeping it a local property would be a preferred way to code it and avoid some "undocumented features" in the future...

Thanks so much for your help!

No problem, glad to help!

You don't need to use a script at all. Indirectly bind the button's value (Toggle button's "selected" property) to the target tag bidirectionally.

That’s true, the only reason I use the script is because the toggle button I use in my example requires a confirmation. I tested it out in Ignition 7.9 and the selected property when bound to a tag will not check to confirm that the bound property is, in fact, selected. Once you click it just assumes that the tag IS true.

By using the scripting shown above I can use a confirmation and clear the selection if the operator cancels.

Of course, if no confirmation is required then yeah, the scripting would be completely unnecessary and your solution would be a much more direct.

Hmmm. I entirely avoid using the confirmation box and messagebox. They have unreliable thread execution semantics. If I need any kind of confirmation before a button is active, I arrange to disable the button until prior confirmation is given.

1 Like