Momentary Button on HMI Writing to MODBUS Server
Creating a Safe Momentary Button for Your HMI
Controlling Overhead Door Openers with a Momentary Button in Perspective Ignition
Overview
Creating a momentary button in Ignition seems like it should be reasonably straightforward, but because I am using Perspective I found that here is no momentary button built in. I tried a couple different scenarios while scripting one and came across some interesting scenarios when attempting to control the overhead door openers in my shop.
Test Environment
- Arduino Micro Controller acting as a MODBUS Server
- Ignition Environment acting as a MODBUS Client and HMI (Virtual Machine)
- Digi IAPs acting as DB9 Serial Ports for the VM
- Microhard Nano 920 Radios providing wireless connectivity between Ignition and Arduino
- Two Overhead doors with remote openers
Door Operation
The overhead doors in question have remote door openers. I have two openers for these doors as well as a few vehicles which can be programmed to open the doors, but I wanted another way to open the doors in case I was in a vehicle that didn't have an opener. Since I can acess my Ignition HMIs from my phone using TailScale, this seemed like a good solution.
Looking at the receivers for the overhead door controllers I noticed that there are two wires for power, and another two wires with the label 'relay'. Momentarially placing a jumper across the relay terminals causes the door to open, or close (depending on its position).
However, leaving the jumper across the relay terminals causes some undesirable behavior.
- If the door is down and I leave the jumper across the relay terminals, the door will open, but once achieves the open position, it then starts to close, goes down about a foot, and then opens again, and repeats this up and down behavior until the jumper is removed.
- If the door is open and I leave the jumper across the relay terminals, it repeats the up and down repetitive motion described above.
Obviously this is not ideal, and leaving the jumper in this position for any amount of time will cause damage to both the motor and the door. What I need is a momentary pulse send to the relay.
Considerations
- Ignition Vision has a momentary button in its tool set, but Ignition Perspective does not.
- Using delays in the Arduino Program interupts communication to the Ignition environment and OPC communications goes bad during the delay period
- Scripts can be triggered in Ignition on 'mouse press' and 'mouse release' but this doesn't seem to work from a phone.
Momentary Button Creation
To solve this problem, I broke it into three pieces.
- A button in Ignition triggering a script to write a modbus register high in the arduino and engage a relay to open the garage door.
- An addition to the arduino programming to monitor the written register and write a second register high when the 1st register goes high.
- The script in Ignition which writes the first modbus register high, monitors the second registers output, and once it sees the second register go high (confirming a successful write), it writes the first register low again.
There are other methods which could be used to achieve this same task, but what I like about this method is it confirms that the modbus server receives the command instead of assuming the command was successfully received. If the HMI, communication path, or arduino were to momentarially lose communication it allows for a fail safe condition instead of leaving the system in an abnormal state.
Ignition Button Code:
def runAction(self, event):
system.tag.writeBlocking("[default]Door1",1)
while (True):
if system.tag.readBlocking("[default]Door1CMDCNF")[0].value < 1:
system.tag.writeBlocking("[default]Door1",0)
break
Arduino code:
int DO02 = regBank.get(2);
//Ignition Server will send a 1 to register 2 when Door #1 Button is pushed
//If 1 is received write relay 3 high to open Door #1
if (DO02 >= 1) {
digitalWrite(relay_3, HIGH);
//If 1 is received on register 2 also set register 4 to 1 so that Ignition server knows that 1 was received
regBank.set(4,1);
} else {
digitalWrite(relay_3, LOW);
regBank.set(4,0);
}
int DO03 = regBank.get(3);
//Ignition Server will send a 1 to register 3 when Door #2 Button is pushed
//If 1 is received write relay 4 high to open Door #2
if (DO03 >= 1) {
digitalWrite(relay_4, HIGH);
//If 1 is received on register 3 also set register 5 to 1 so that Ignition server knows that 1 was received
regBank.set(5,1);
} else {
digitalWrite(relay_4, LOW);
regBank.set(5,0);
}