Timer script executing multiple times

Script with syntax highlighting
##########################################################
# 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

Varsha, please see Wiki - how to post code on this forum.

1 Like