Tag change script advice please

Hi All

I’m using ignition to log data from a heat treatment furnace controller via ModbusTCP. We read three variables.

  • Temperature (float)
  • BatchStatus (running or not)
  • BatchNbr (integer)

System characteristics.
The operator presses the start button on the machine (hardware). The BatchStatus flag goes high and the BatchNbr variable is incremented by 1. The machine runs its cycle and at the end, BatchStatus goes false.

I have written a script which populates a simple SQL table with the BatchNbr and the start and stop
timestamps. Using this lookup table, I can then query ignition’s tag historian for the temperature profile associated with the heat treatment batch. This is used by the reporting module to print out a cert for the batch. The script is currently triggered from value change on BatchStatus. This all works fine. Sort of.

Occasionally there is a delay between the BatchStatus going high and the BatchNbr incrementing. I’m not sure if this is a charactestic of the machine or ignition’s polling rate. Anyway, this results in a race condition. If BatchNbr increments first, this causes no problems. However, if BatchNbr increments after BatchStaus, the new row in my lookup table is populated with the batch number of the previous run.

I have thought about triggering based on BatchNbr, but this doesn’t change at the end of the run - only at the start of a run.

I have made this work using a 1 second sleep which is not ideal. See code below. When the BatchStatus flag goes high, the script waits for 1 second to allow the BatchNbr variable to be incremented. The SQL commands are then generated and executed. This works well but, having read a bit about it, I’m not keen on leaving the sleep function in place.

I’ve tried invoke later with no luck, but I understand that this does not work on gateway scripts (client only).

  1. Does anyone have any suggestions for improving the sleep section of this code? An improvement would be to have some logic which determines if the BatchNbr variable has also changed
  2. Which is preferable, adding the script to Gateway Events or leaving it as a Tag Event Script in the tag editor?

Thanks.

def valueChanged(tag, tagPath, previousValue, currentValue, initialChange, missedEvents):
	"""
	Fired whenever the current value changes in value or quality.

	Arguments:
		tag: The source tag object. A read-only wrapper for obtaining tag
		     properties.
		tagPath: The full path to the tag (String)
		previousValue: The previous value. This is a "qualified value", so it
		               has value, quality, and timestamp properties.
		currentValue: The current value. This is a "qualified value", so it has
		              value, quality, and timestamp properties.
		initialChange: A boolean flag indicating whether this event is due to
		               the first execution or initial subscription.
		missedEvents: A flag indicating that some events have been skipped due
		              to event overflow.
	"""
	
	from time import sleep
	 
	# This will pause execution of the script for 1 second. This delay allows the batch number to
	# update as there is often a delay of a few ms after the batch status flag goes high.
	sleep(1)
	
	# Set the table
	tableTime = "STS_HT_Time"
	Database = "hamjet_report"
		
	# Read the system time
	timeNow = system.tag.read("[System]Gateway/CurrentDateTime").value

	# Read the new (or current) batch number.
	batchNow = system.tag.read("[HamJet_Tags]Stainless Steel/Heat Treatment/BatchNbr").value
	
	# If the batch status has changed to 1 (from 0) then...
	if (currentValue.value == 1 & currentValue.quality.isGood()):	
	
		#set the arguments for the SQL query,		
		args = [batchNow, timeNow]
		
		# Build the query string
		command = "INSERT INTO " + tableTime + " (BatchNbr, StartTime) VALUES (? ,?)"
		
		# Run the query
		system.db.runPrepUpdate(command, args, Database)		
		
	# If the batch status has changed to 0 (from 1) then...		
	elif (currentValue.value == 0 & currentValue.quality.isGood()):
		
		#set the arguments for the SQL query,
		args = [timeNow, batchNow]
		
		# Build the query string
		command = "UPDATE " + tableTime + " SET StopTime = ? WHERE BatchNbr = ?"		
		
		# Run the query
		system.db.runPrepUpdate(command, args, Database)

One way to improve is to create a diagnostic alarm with an active delay of 1 second, then you do your script on the Alarm Active event on the tag. That way you don’t need to use sleep at all.