I tried reaching out to Ignition technical support but looks like they don’t support 7.7.1 anymore. We are having issues with some timer scripts. We run Batch Program on multiple tanks. The active Tank recipes are loaded to a database. We have different operations and Steps withing operations. Operators use UI’s to flow through the operations. PLC holds the information in tags like Operation ID, step etc..A done button for example on the UI tells the PLC that a particular step is completed and moved to next step. Apart from this there are also two scripts, A tag change script that logs to a database every time the operation or step tags change(There is a unique Batch record code) for each step and a Timer Script that continuously browse through the current recipe table in the database and Batch record code. This timer script sometimes executes multiple times within a second which causes skipping within steps and operations sometimes. The issue is intermittent, so I cannot say it is a badly written script. I see that people had issues with Timer scripts executing multiple times. Engineers at our plant explored options to allocate more resources like memory to run Ignition. The issue did not resolve. Please help. I have a Wrapper log that is hard to understand.
##########################################################
# NAME: goToNextOp
# DESCRIPTION: When an operation has been completed, set that operation
# to "COMPLETE" in the database, signal the PLC to reset the operation
# status and wait until it is finished, then set the next operation in
# the database to "RUNNING". When a running operation has been found, it
# copies the new operation's information from the database to the PLC
# batch program.
# PARAMETERS: PLCbubbleNum (active bubble number in the PLC, if this does
# not match the bubble number from the database, then the
# PLC information needs to be updated.)
# opComplete (trigger from PLC indicating an operation has finished)
# REVISION: 1.3 08/31/17
# REV. NOTE: Added "nextOpStep" to prevent issues where certain functions are
# repeated or triggered out of order.
##########################################################
# send a query to the DB, requesting all running operations
#RU 03/05/2019 -- Update query so that it also obtains all the PAUSED operations
#RU 09/13/2019 -- Update query so that it also obtains all the PAUSED-APP6 operations
table = system.db.runQuery("SELECT * FROM RUNNING WHERE STATUS='RUNNING' or STATUS='PAUSED' or STATUS='PAUSED-APP6'")
commDelay = [False]*75 # if set to true, this means the 'opComplete' bit has
# already been read, so the batch should not be processed again
batchCleared = False # indicates batch has been cleared, so OP_ID should not be modified
# update cycle number for logging/debugging
cycleNum = system.tag.read("IgnitionStatus/GoToNextOpCycle").value
if cycleNum > 9999:
cycleNum = 0
else:
cycleNum = cycleNum + 1
system.tag.write("IgnitionStatus/GoToNextOpCycle",cycleNum)
cycleNum = str(cycleNum)
# CHECK FOR RUNNING OPERATIONS IN THE DATABASE
for row in table: # iterate through all running operations that were found
vesselID = shared.Functions.vesselID(row[0][1:]) # change vessel name to vessel ID
tagPath = "Vessel/Vessel_" + vesselID + "_/Batch/BubbleNum" # set tag path
PLCbubbleNum = system.tag.read(tagPath).value # get current bubble number from PLC
nextOpStep = system.tag.read("IgnitionStatus/NextOp_Step_" + vesselID).value # get nextOp step number
# if current bubble number of the operation does not match the db value
# and steps 1 and 2 have already been completed (or it is the first operation
# in the batch), then start the next operation.
if (PLCbubbleNum != row[2]) and (nextOpStep == 3 or row[2] == 1):
if system.tag.read("Vessel/Vessel_" + vesselID + "_/Batch/OperationComplete" ).value == 0:
print "Cycle:" + cycleNum + " 3. Bubble: " + str(row[2]) + " started on vessel " + row[0][1:] + ". Old bubble number=" + str(PLCbubbleNum)
system.tag.write(tagPath,row[2]) # write new bubble number to PLC
system.tag.write("IgnitionStatus/NextOp_Step_" + vesselID,1) # update nextOp step number
shared.Functions.startOperation(row,vesselID) # start operation function
else: # opComplete has not been cleared, do not start the next operation yet
commDelay[int(vesselID)] = True
print "Cycle:" + cycleNum + ", waiting on opComplete for vessel " + row[0][1:]
tagPath2 = "Vessel/Vessel_" + vesselID + "_/Batch/CurrentStep" # set tag path
if system.tag.read(tagPath2).value == 0: # current step = 0 found, always start on step 1
print "Step 0 found on vessel " + vesselID + " - reassigned to step 1."
system.tag.write(tagPath2,1)
#moved checking for PAUSED operation in a different script
#RU 03/26/2019 Add the following line of code to determine if the lot is an adjustment.
current_OPID = system.tag.read("Vessel/Vessel_" + vesselID + "_/Batch/OP_ID")
if current_OPID.value == 1:
currentLot = system.tag.read("Vessel/Vessel_" + vesselID + "_/Batch/ProductLot/STRING")
currentLotLen = system.tag.read("Vessel/Vessel_" + vesselID + "_/Batch/ProductLot/LEN")
checkAdjPath = "Vessel/Vessel_" + vesselID + "_/Adjusted"
if currentLot.value[currentLotLen.value - 1] == "0":
system.tag.write(checkAdjPath,0)
else:
system.tag.write(checkAdjPath,1)
# CHECK FOR COMPLETED OPERATIONS AND MOVE TO NEXT BUBBLE NUMBER
i = 1 # initialize vessel ID index for searching
while i < 74: # look through each vessel
j = str(i) # convert vessel ID to string
opComplete = system.tag.read("Vessel/Vessel_" + j + "_/Batch/OperationComplete" ).value
opID = system.tag.read("Vessel/Vessel_" + j + "_/Batch/OP_ID" ).value
# if an operation is complete, and the PLC has been changed to "loading",
# and the operation has not already been changed, then continue to next operation
if opComplete == True and opID == 100 and not commDelay[i]:
# reset batch control tags first
system.tag.write("Vessel/Vessel_" + j + "_/Batch/OperationComplete",0) # unlatch op complete
system.tag.write("Vessel/Vessel_" + j + "_/Batch/CurrentStep",1) # reset current step
system.tag.write("Vessel/Vessel_" + j + "_/Workflow/HMI_PB/HMI_PB_0_",0) # unlatch done pb
vessel = shared.Functions.vesselName(j) # load vessel name
# get the currently completed operation to ensure it exists in the database
currentOp = system.db.runQuery("SELECT TOP 1 Operation FROM RUNNING WHERE STATUS='RUNNING' AND VESSEL='V" \
+ vessel +"'") # find the completed operation
nextOpStep = system.tag.read("IgnitionStatus/NextOp_Step_" + j).value # get nextOp step number
if len(currentOp) > 0 and (nextOpStep == 1): # confirm that the operation exists in the database
print "Cycle:" + cycleNum + " 1. Completed operation " + currentOp[0][0] + " found on vessel: " + vessel
# If the completed operation is 'FILL', record filter data
if currentOp[0][0] == "Fill":
print "Fill operation completed, filter data recorded on vessel " + vessel
shared.Functions.recordFilterData(j)
system.db.runUpdateQuery("UPDATE RUNNING SET STATUS='COMPLETE' WHERE STATUS='RUNNING' AND VESSEL='V" \
+ vessel +"'") # update completed operation to COMPLETE
nextOp = system.db.runQuery("SELECT TOP 1 * FROM RUNNING WHERE STATUS='PENDING' AND VESSEL='V" \
+ vessel + "' ORDER BY BUBBLE_NUM ASC") # find next PENDING op
system.tag.write("IgnitionStatus/NextOp_Step_" + j,3) # update nextOp step number
if len(nextOp) > 0: # Additional pending operations exists
nextOpNum = str(nextOp[0][2])
system.db.runUpdateQuery("UPDATE RUNNING SET STATUS='RUNNING' WHERE BUBBLE_NUM='" + nextOpNum + \
"' AND VESSEL='V" + vessel +"'") # set next op to RUNNING
print "Cycle:" + cycleNum + " 2. Set bubble number " + nextOpNum + " to 'Running' on vessel " + vessel + "."
else: # There are no more pending operations, batch is complete
shared.Functions.clearBatchValues(j) # clear batch values
batchCleared = True
system.db.runUpdateQuery("DELETE FROM RUNNING WHERE VESSEL='V" \ # remove the batch
+ vessel + "'")
print "Cycle:" + cycleNum + " No more pending operations for vessel: " + vessel + ", batch removed from DB."
else: # batch does not exist, send error indication to PLC/iFIX
system.tag.write("Vessel/Vessel_" + j + "_/Batch/OP_ID",99) # 99 = operation error condition
opComplete = False
system.tag.write("IgnitionAlarms/IgnitionAlarms_1_",vessel)
print "ERROR: Vessel " + vessel + " has a completed operation but does not exist in the database!"
# set current vessel to 'loading'
elif opComplete == True and opID != 100 and not commDelay[i] and not batchCleared:
system.tag.write("Vessel/Vessel_" + j + "_/Batch/OP_ID",100)
print "Cycle:" + cycleNum + "OP ID set to 100 ('loading') for vessel " + j + "."
i += 1 # increment vessel ID counter