MousePressed and MouseReleased component script

Hi All,

I am migrating a project from WonderWare to Ignition and there are many buttons that are supposed to set a PLC tag when pressed (after checking another tags value is 0) and the reset it when released.

I have a component that I drew in Ignition that on MousePressed, checks a tag is 0 and if so, sets the PLC bit:

paths = [
values = system.tag.readBlocking(paths)
AutoSelect =  values[0].value

if AutoSelect == 0:
	system.tag.write('[default]tag', 1)

I then have a MouseReleased script that resets the bit:
system.tag.writeBlocking(['[default]tag'], [0])

A major problem we are seeing this morning is that if the button is pressed then released too quickly, the bit stays on. I have even tried removing the part of the code that checks if the other tag is 0 first with no change.

Anyone experience this before?

If I switch the functionality to a momentary button where I bind the tag to the Control Value property it seems to work fine so that is an option but then I am not able to do the check logic. I can overcome this by binding the Enabled property to the check tag I guess...


Danger Will Robinson!

You are trying to implement Momentary pushbuttons from scratch. It is nearly impossible to make them reliable. Even the built-in Vision momentary button exhibits this behavior sometimes.

Fundamentally, any SCADA that does this must send two messages, and either can be dropped or delayed in pathological ways (dropping the "release" message being the concern). In SCADA with a central point connecting to PLCs, there are two paths for messages: Client to Gateway, and Gateway to Device. This raises the odds of message loss.

Some "light" reading:

If you must have Momentary buttons, it will be difficult to make it reliable unless the Gateway-to-PLC connection uses an I/O protocol (which is the original raison d'être for my EtherNet/IP module), and the Client-to-Gateway messages are fast repeating "I'm still pressed" indicators. The key is repeating messages all the way along the path where the PLC can monitor the message arrivals and use a fast timeout to cancel.

TL/DR: Don't convert these momentary buttons. Redesign the system to not need them.


Hi Phil,

Thank you so much for your quick reply as I was about to convert everything because I have not yet seen the momentary button I put in for testing this morning not work yet.

The WW system I am converting from has been in production for decades so I am surprised it has not had this issue before. WW communicates serially to the device and Ignition communicates Modbus TCP/IP.

This did unfortunately have bad consequences at our plant so I have ceased Ignition control until I decide on and switch to a way that this is no longer a concern.

These are my current best ideas:

  1. Reprogram PLC to reset these bits if they are set (at the very end of the ladder program).
  2. Remove the mouseReleased event script, and instead place a tag event script - something like this:
if currentValue.value == 1:
	system.tag.writeBlocking(['[default]tag'], [0])

I agree that it's best to design things to not use momentaries because of all the things already pointed out.

Another thing to watch out for when dealing with momentary buttons is that some touchscreens have an "untouch timeout" which will make the button release on a click and hold. There is also a windows setting that by default will turn a long held "touch" into a right click (disable that).

I'm firmly in the camp that momentary buttons are best avoided.

Sorry, no.

  • Resetting a bit in the PLC after set by Ignition has odd race conditions when using an OPC tag. If you use a "fire-and-forget" scripted OPC write (via system.opc.write* instead of via a tag), then it isn't so bad.

  • With that tag event, you can get the set and release so close that the PLC scan doesn't see it.

If you cannot use a reliable protocol, the best option is to use a short integer instead of a boolean. Use a timer in the PLC to make a pulse when the integer changes, and keep the pulse on if the integer keeps changing. Send repeating messages from the client as long as the button is pressed that increment the integer. There's no good way to do this in Perspective, unfortunately. Such a button can be created in Vision. I recommend a PLC rung like this one:

I recommend sending a "1" to PBTrigger when the button is first pressed, then incrementing at a 100ms pace, then sending a "0" when the button is released to cut off without waiting for the timeout. The increment logic needs to skip 0.

In that logic, PBPulse.DB is to be used in the PLC instead of the original pushbutton boolean tag.

1 Like

Oh boy, I feel I have opened a can of worms!

Resetting a bit in the PLC after set by Ignition has odd race conditions when using an OPC tag.

Is this because system.tag.writeBlocking does more than simply changing the value of a tag? Perhaps it also then verifies that the tag did change as intended? If this is the case, the concern would be what happens if the PLC resets the bit before writeBlocking verifies itself? What would Ignition do in this circumstance? It would not try again right? This is not (or less) of a concern when using system.opc.write?

Can you give me an example of what else could go wrong? Have you experienced such issues before?

It is mostly in relation to bidirectional bindings. They try to see the write value in the next poll to confirm the write succeeded. (The write in progress border overlay.) A tag can be set to optimistic writes to not care, and that helps with some cases. But OPC writes and subscription reads are fundamentally independent. Change events can be missed.

If you aren't reading the tag at all (or bypassing the tag system so it doesn't care), then there's no chance for a race. "Write success" is simply the PLC reporting that it did the write as requested.

1 Like

For clarity, the PLC does not require the tag to be on for a certain duration or anything, it just sees that if the tag is set (among a few other conditions), it will initiate a particular process in the real world (pump product from tank A to tank B). It only needs to be reset so that command does not conflict with another command later in the day. The issue we had this morning is that the tag remained set so when a different command bit was set (pump product from tank A to tank C) there was a conflict of what to do and so it just kept on pumping into tank A which resulted in lost product.

Any momentary button that is only used as an edge trigger in the PLC can be replace with a fire-and-forget set operation in an normal (non-momentary) button's actionPerformed script. Then immediate reset in the PLC is fine.

Arguably, you've exposed a part of the PLC code that should have had "anti-tie-down" logic, because real physical buttons can be jimmied by operators to stay on.

The real issue is jog functions that really do expect to operate while pressed and stop when released.

1 Like

Thank you for all of your insight Phil, very much appreciated!