Momentary Pushbutton latching ON

Correct. This method is now in a live system and there has been no reports of latching after many thousands of clicks. Of course, as mentioned previously, there is always the possibility of latching if gateway > plc coms are interrupted.

1 Like

If its a communication issue between PLC and gateway, why don it happens for all momentary buttons that I have. I have several of momentary buttons and it happens only for three of them. Also, I have a fiber optic communication between my gateway server and the PLC node.
So, there could be something else.I tired to compare with the other momentary button that don’t have any issues, everything seems to be same. I re-created another momentary button and it does same.
I am not an expert in this, but some of the question that arises, is it possible to make another property to reset its value back to original with in a certain time, say 1000 ms or so… Don’t know, if its a stupid thinking…

Did you actually try the solution above? The issue we have (sort of) resolved is the issue of intermittent latching... in the neighborhood of 30-60 clicks there will only be a single latch of the PLC bit. If you are getting constant latching, then your issue is probably somewhere else.

As you were...


As you mentioned, I was trying to select the 'OPC Read after write for the scan class that are associated with this momentary button. But I don't see this option under my scan class editor.
Is it same as OPC Data mode selection, where I have tow options as subscription and Read.
Is it the one needs to be changed to Read?

I don't have a tag editor as shown in Sander Deryckere post

Your version of Ignition appears to not have the settings you need. It is ancient. At least try v7.5.14 if you cannot upgrade beyond that. But seriously, if you need highly reliable momentary pushbutton behavior, you will have to implement repeat signaling code in both Ignition and in the PLC to cover all of the cases.

1 Like

Perhaps you didn't grasp the core of the problem -- it isn't Ignition, it is the nature of request-response protocols. This problems exists in every product I've ever used over my 30 years in this business, with every brand of PLC and every brand of HMI. If they used a request-response protocol. Serial, ethernet, DH+, Siemens, Modicon, Allen-Bradley, and others. Even tag access over mixed technologies like DeviceNet and ControlNet. Didn't matter. All showed this problem. Products that implement the specific PLC's I/O protocol can be trusted with momentary buttons. Nothing else.
Products like Ignition that consolidate PLC traffic to a gateway, and then all HMI traffic goes through that gateway, do suffer from a higher chance of losing a release event, as there is another link in the communication chain compared to the direct connection of simple HMIs. And yes, there are corner cases that lose a release like closing a window while a button is pressed. But read the documentation for direct HMIs like AB's Panelview -- there are warnings about using momentary buttons over non-deterministic (I/O) protocols.
For an SLC, the only deterministic protocols supported directly are classic AB-RIO, DeviceNet (as an I/O slave, not tag access), and Profibus (the latter via third parties). Use one of those with a direct HMI for absolutely reliable touchscreen pushbuttons. Use a direct ethernet HMI for almost as reliable pushbuttons. Use repeating signalling with corresponding PLC code timeouts with anything else. Ignition or not.

There is nothing for IA to fix in Ignition.


A signalling approach to consider to minimize the PLC code required:

  • Allocate a PLC array tag / file with enough integers to cover all of the momentary button bits you need for your application, plus two more for transmit counter/comparison at the end. Do not create Ignition tags for these PLC tags.
  • Create a script module in Ignition that holds an array of timestamps for the number of bits needed, plus a persistent counter in a module global. Write two functions:
  • A message handler that takes a bit number and sets the corresponding timestamp to some number of milliseconds in the future. 150ms or so.
  • A gateway timer event function that loops through all of the timestamps, treating all in the past as 0 and all in the future as 1, packing the results bitwise into integers, appends the incremented counter, and writes them all to the PLC in a single system.opc.writeValues() call. Does not write to the last register in the array/file. Call every 100ms or so.
  • Write a few rungs in the PLC to check the last integer against the second to last, run a timer while equal, then copy the Ignition counter to the last register. If/when the timer expires, 200ms or so, (broken comms), fill the array with zeros.
  • In a client window, create a timer component with a 100ms period. In its actionPerformed method, use system.util.sendMessage() with a specific bit number.
  • In the same client window, create a momentary button for that bit and bind its value to the timer component’s enabled property. Do not bind it to any tag.

Create as many timer/PB pairs as needed, up to the capacity of the PLC array (less the last two words), each with their own bit numbers. Use the corresponding bit in the PLC as a reliable normally-open PB.

Any lost messages, lost OPC writes, or Client GUI freezes will yield a zero bit in the PLC.


Good day, shibubalaji...

shibubalaji: I some cases, I have seen instances where dialog boxes do not always reveal all options and must be "mouse grabbed" and dragged down to enlarge the box and show all. But in your case, I believe it is a version issue. Please carefully consider Mr. Turmel's excellent replies to you question(s) and act accordingly.

Phil... thank you for your eloquent and thorough replies.

As you were...

Reviving topic to ask - assuming conditions such that synchronous implementation is reliable (I know this is a dangerous assumption, purely hypothetical) and we don’t need to worry about freezing the HMI, would using system.tag.writeSynchronous() eliminate the race? Thank you in advance

The core problem is not a race condition. It is simply the potential failure to deliver the message that writes to the PLC (resets the bit) when the button is released. That failure to write to the PLC can be caused by any failure in any device or network or piece of software between the user and the PLC. Leaving the signal turned on in the PLC. Some of the mitigation techniques have race conditions that make them unreliable, too. Using system.tag.writeSynchronous() doesn’t change the path the message must follow, nor make it more reliable.


I really appreciate this solution, but I thought of a variant that I was hoping you could provide feedback on, in case I am overlooking something.
Disclaimer: This solution is intended for the assumption the operator is only interacting with one PB at any given time.

-PLC uses a [1x2] array, storing an integer, and a boolean
-Instead of a timer event function, this utilizes a Tag Change - triggered by an Expression Tag (known in this description as x), which stores an integer

  • timer enabled: x = 0 (change triggers script), x = some unique index associated with this PB (change triggers script)
    -when a PB timer is disabled, x = negative unique index (change triggers script)
    Timer event function:
    -when switched to 0, do nothing
    -when switched to positive integer, send [x,1] to PLC
    -when switched to negative integer, send [-1 * x,0] to PLC

-timer to check for broken comms
-stores a last received index, defaulted to -1
-new index,value pair received, reset timer
-value = 1, set tag corresponding to index, last received = index
-value = 0, reset tag corresponding to index, set last received = -1
-implement simple error handling regarding unexpected index values
-Note that the indices should be indexed by 1, not 0

I think this will decrease the memory needed, so for large numbers of PBs it should increase speed, and remove the constantly running timer, but will also require more PLC code.
Is there anything in here you think I am overlooking/any reason why this isn’t a viable solution?
Thank you for your help!

It doesn't address any of the failures between the user interface (Vision/Perspective) and Ignition.

I also think it unrealistic to expect only one momentary PB to be pressed at a time across your entire gateway/clients/designers. Unless you have code to enforce it, at which point a general solution starts to make sense.

You are right, if for some reason the ‘OFF’ condition isn’t triggered by the release, the button would continue to run. I think including a check in the enabled script of the timer to the controlValue to make sure it is still held down would fix this. Are there any others I am overlooking?
As for the usage of only one PB, we only use them in one application that is only instanced once - and don’t intend on including them in the future. In general though, I agree that it is a big assumption.

Perhaps you should start over at the top of this topic and review all of the various ways a button-release event can fail. Over the entire path to the PLC. I don’t see how your recommendation covers the cases.

The solutions that appear to cover all of the bases invariably use a quickly changing signal from the client that affirmatively indicates that the button is still pressed, with a short timeout at the PLC. Ensuring that the changing signal originates on the GUI thread (in Vision) is crucial to catching GUI thread crashes. This approach is typically accompanied by some housekeeping logic that ensures that once a timeout expires, the button must affirmatively transition from off to on again before it is allowed.

Thank you for the response, I have gone through the thread and your solution again, and have a few questions.

Am I misunderstanding, or is this not functionally identical to the controlValue check before initiating any action that I mention in my previous comment? If the check fails, cleanup.

The other sources of failure I know of are GUI freeze and gateway-plc comms failure, both of which I think are covered by the PLC timeout, as no new writes will be sent, and window closure while pressed, which I believe should cause the controlValue check to error (along the lines of component does not exist).

Thank you for this, I can imagine safety issues if a queue of pending "move"s were to form. I think saving the response code from system.tag.write and running cleanup and throwing an error window if it is not 1 should account for this. Although there is a chance this could still queue one move (I don't think it would, but can't find affirmative documentation as to what "immediately" constitutes, and whether it is less time than the PB timer), this could be fixed PLC side by requiring 2 consecutive 1 writes in the same index in order to move. Could easily use last_received for this, and the delay should be almost imperceptible to the operator, being at most 1/20 of a second.
Thank you again.

No, an expression tag doesn't guard any traffic from the GUI.

How will your expression tag know the GUI is frozen or comms are lost to the client?

How will the PLC know you've written the same value twice to the same location? If you reset it in the PLC in between, you are setting yourself up for races--see my notes about only writing a given regster from one direction.

default state of PLC: all associated PB tags = 0
last_received = -1
signal (i,1) received
if tag[i] == 0 && last_received == i { tag[i] =1}
else if last_received != i { last_received=i}

So the first time it will just set last_received, saying "there is a precedent for this message", and the second one will actually turn it on. Any PLC timeouts or other signals will reset this count, although that logic isn't included in this comment, just for simplicity.

This is incorporated into:

I was under the impression that if the GUI froze, the script associated with the timer would not run, but I am new to Ignition so you would certainly know better than I. For my reference - could you direct me to which aspect of your solution protects against a frozen GUI, as well as "guard[ing] against traffic from the GUI".
Thank you

Expression tags run in the gateway. If you aren't scripting in the gateway, then maybe your solution satisfies this part. Like mine:

The actionPerformed event runs on the GUI thread, so if the GUI chokes, the message won't be sent. If the messages aren't sent on a steady pace, or comms go down, the gateway side will see that signal's stale timestamp and kill it.

Thank you, I didn’t explicitly mention it in my original write up, but the timer I reference is bound to a PB in the same configuration. I believe the only difference is what is done in the actionPerformed method. Does this mean I can assume that frozen GUI => actionPerformed won’t run => no Expression Tag change => Tag Change script doesn’t run => No write sent ?

Yes, that looks correct.

1 Like