Perspective Button to Toggle OPC tag value

I’m trying to create a button in Perspective to toggle a Boolean OPC tag.
In view I use the ‘mouse release’ in a script to set the bit.
It is not readily apparent how I do this in Perspective.

Thanks,

It is a similar setup. There are events that match to similar cases as in Vision, and then you can select a list of pre-defined actions. One of those is 'Script' which would allow you to use a very similar script(or maybe even the same depending on logic) to what you used in vision.

https://docs.inductiveautomation.com/display/DOC80/Perspective+Events+and+Actions#PerspectiveEventsandActions-ScriptAction

There are lots of ways to accomplish this in Perspective, with the two “easiest” being a script which reads/writes the tag value, and the other being a simple negation of a bound property. The bound property is the easiest, so I’ll show you how to do that.

  1. Place your Button.
  2. In the Perspective Property Editor, locate the “CUSTOM” category for your Button, and click “Add Custom Property”.
  3. Rename this property to some key which means something to you (I will rename mine “current_tag_value” for the purpose of this example).
  4. To the left of this new property, click the binding icon (looks like chain links).
  5. Select the “Tag” binding type.
  6. In the configuration panel, specify the path of the tag you want to toggle (I recommend also specify the “.value” at the end to specify that you are binding against the value of the tag).
  7. Click the “Bidirectional” checkbox located just below the Tag Path text input.
  8. Click OK.
  9. Right-click your Button and select “Configure Events”.
  10. Select the triggering Event which you would like to toggle the tag value (I recommend onActionPerformed or onClick, but you could use onMouseUp if you prefer).
  11. Click the “+” Icon to the right of the “Organize Actions” area, and select “Script”.
  12. Supply self.custom.current_tag_value = not self.custom.current_tag_value as your script code.
  13. Click OK.

You should now have a button in place which will set the custom property to whatever the negation of its current value is (so toggling a binary true/false value) whenever the selected Event occurs.

17 Likes

It’s still not clear to me how to write the script.
Can you show me and example?

Found my problem, I was not setting the button for bidirectional.

Thanks,

Great work. Very helpful and clear.

2 Likes

I tried this method on a tag with write security set using a user who doesn’t have permission to write. The button doesn’t work as expected, but the system is not showing a message about insufficient user rights.

@Ali.Etezadkhah : I just replicated the steps I provided previously while working with a tag which has write permissions set and I did encounter the expected notification for not having the required permissions.

Could you provide screenshots of your own setup which include the tag, binding configuration, and security requirements for the tag?

1 Like

@cmallonee I must have missed a step. I just tried it again and it worked. Thank you for the step by step guide.

1 Like

This method worked for me…kind of. The boolean tag gets modified, but the button I’m using to activate it turns grey and says “Writing…” with an hourglass beside it. This leaves the button inoperable without closing and restarting the session. I have confirmation enabled, and if I click “no” to the “are you sure” question, the button remains enabled and the bit gets modified, which shouldn’t happen because I clicked “no”, indicating that I don’t want to execute the command. If I click “yes” or disable confirmation, I get the greyed-out button with “Writing…” and the hourglass.

@mike.knauss : You’re using a One-Shot Button instead of a normal Button, and this will prevent you from toggling the boolean value back. This walkthrough was only intended for use with a regular Button. I’ll look into your use-case tomorrow to see if I can replicate the issue and how best to work around it or resolve it.

Yep, it works with a regular button. Thanks!

Okay, I finally had the time to wrap my head around the One-Shot Button use-case, and there is a big reason my current recommendations won’t work there, but there are alternate routes for the same functionality - but the alternate route will never look quite right.

Why the aforementioned setup won’t work for the One-Shot Button:
The Button component is “state-less”, whereas the One-Shot Button has states (ready, writing). Basically, the Button component will look the same and behave the same no matter what the value is or what it’s being set to; this is why it’s good for toggling between two states (though obviously not as good as a Toggle Switch or Checkbox). The One-Shot button is in one state while the driving value (props.value) is different then the “set value” (props.setValue), and it’s in a different state when the value is the same as the set value. So there is actual logic driving the appearance of the One-Shot Button based on a comparison of props.value and props.setValue.

Well, why does this matter if we’re using a custom property?

It matters because while the custom property is not changing ( I verified this locally, and the security permissions are behaving exactly as I’d expect), the button click IS changing props.value to the set value. Since props.value is the property driving the appearance, you get the illusion that the tag has changed value, but props.value is in no way indicative of the tag value. If you had bound props.value to reflect the value of your custom property you’d have seen that no changes were occurring.

Alternate route for One-Shot Button:
Since the One-Shot button changes state based on a comparison of props.value and props.setValue, you have to make sure those two values are different, which means you need to swap their values as part of your tag change, BUT doing this will result in some weird race conditions, and the end result is that you’ll be using a One-Shot button while circumventing all of the logic which makes the component useful, just to end up with a component that looks and behaves just like a Button.

But the alternate route would be that instead of binding against a custom property, you just bind props.value instead of the custom property, and you’ll need to include a script to change the set value so that the button will allow for toggling back to the alternate value:

	def reset_set_value():
		from time import sleep
		sleep(1)
		self.props.setValue = not self.props.value
		
	system.util.invokeAsynchronous(reset_set_value)

Hi - I followed your instructions and I can toggle my button and it works in the PLC, however, I am getting an error message -
com.inductiveautomation.ignition.common.script.JythonExecException
Traceback (most recent call last):
File "function:runAction", line 2, in runAction
AttributeError: 'com.inductiveautomation.perspective.gateway.script' object has no attribute 'current_tag_value'

caused by org.python.core.PyException

Traceback (most recent call last):
File "function:runAction", line 2, in runAction
AttributeError: 'com.inductiveautomation.perspective.gateway.script' object has no attribute 'current_tag_value'

Ignition v8.1.20 (b2022082313)
Java: Azul Systems, Inc. 11.0.15

Any thoughts?

That example is predicated upon you having created a custom property on the Button, where you've modified the key of the custom property to be current_tag_value. Until you create that property, the script won't work.

1 Like

Is there a way to make this button act as a momentary PB instead of a toggle? Press the button and it sets a Boolean tag value to 1, release the button and it resets that Boolean tag value to 0. Would this require a different scrip or a different action?

Due to the nature of perspective being web based, I believe the general consensus is that you should avoid trying to make buttons momentary in perspective.

If you have a system that does require it, you'll need to script it to do so properly (send a 1/true, then some time later send a 0/false, but don't use the sleep function as it will freeze your graphics while it "sleeps")

Edit: I've been informed it will not freeze perspective...but still avoid it.

1 Like

Cannot be "properly" scripted in the Perspective UI either. At best (but still not great), you can use a gateway timer event to monitor and reset such things.

2 Likes

Not for perspective it won't, but still not good to use

Really? I figured it would cause any client to freeze up for that amount of time.