Dynamic OPC path

Is there a way to have dynamic OPC path for a tag ?

In PLC I have a tag array structure:
Tag BatchDuration path= [PLC]BATCH_REPORT[X].BATCH_DURATION
Tag BatchStartTime path= [PLC]BATCH_REPORT[X].BATCH_START
etc. etc.
where x (batch number) =1…100

I want to address individual batch from Ignition client.

But it looks like there is no way to change X dynamically ? For example by some reference tag.
path= [PLC]BATCH_REPORT[{BATCH_NO}].BATCH_DURATION

I could import ALL batch report tags into project and then change which tag I am accessing from
user interface, but that would import tens of thousands tags (for all 100 saved batches), when I only need data from one batch at a time.

I think the most dynamic you can get without using system.tag.configure to actually reconfigure/edit your tags is a UDT where you use a parameter to construct the OPC Item Path.

Probably not as dynamic as you’re looking for.

Alternate approach could be to use memory tags and do a bulk system.opc.readValues to populate them for each batch you are going to deal with.

Another alternative is to have the plc handle the writing of batch data into temporary tags which igntion reads. Igntion writes to an index tag telling the plc which batch to read, then writes to a bool to tell it to move that batch data into the temp tags for igntion. It’s a bit slower as you then have the plc as the middle middle man, but it might solve your issue.

I may be off with the use case, but I would suggest doing a parameterized path like Kevin mentioned, but I don’t think it would be as difficult as he thinks to make it change. In 8.x, parameters can be written to like normal tags. Having a reference tag configured like the following will allow you to easily bind to the parameter and change it on the fly like any other tag:

I am attaching an export of my definition here. If you bind any component to the opcItemPath of the members in a UDT Instance, you change the value of _conf/motor_number you can see how everything updates. Example.json (1.5 KB)

Depending on how many parameters are needed, you will want to add a number of protections around this to ensure that the tags referenced are the ones you want. As tag writes are asynchronous, there is no guarantee that all values will populate at the same time.

Garth

4 Likes

I have tried with UDT parameters, and it works if I change the parameter manually.
But I cant bind parameter to a tag. It works only one way - when I change parameter,
the tag connected to that parameter updates. But not the other way.

Searching in the forums I have found similar request and it looks like 10 years ago that was not possible. Has that changed since ?

Binding to parameters wasn’t possible in 7.x versions of Ignition, but it is possible in 8.x albeit not directly. You have to create a Reference type memory tag in 8.x to reference the parameter which will allow you to directly modify the parameter (see above screenshot and example).

Garth

Got it working. Thanks.
Just had to write [.]/Parameters.BatchReportNo instead of [.]…/Parameters.BatchReportNo

Wow, I knew all of that but it never clicked that I could actually use it in that way to make dynamic changes to my tag opcitempaths. That's awesome :smiley:
Damn, that would be far better I think for my recipe editor tags....... Next time!

Would it be possible to make changes to underlying tag JSON?

I have a UDT where I would like to be able to either read values directly from OPC or Reference tags. In both cases, I have parameters.

Is there a way to write a initiate function to assign the binding properties in the JSON of those tags but when I try to assign the binding it actually grabs the value for those parameters and sets that as a binding.

here is my value changed event script for setup tags in the UDT :

	import system
	# Globals 
	valueSourceBindingMap = {"opc":		{"opcItemPath": 	{
													    "bindType": "parameter",
													    "binding": '{opc_device}_Meta:{opc_path}/{TagName}'}
										},
							"reference":{"sourceTagPath": 	{
													    "bindType": "parameter",
													    "binding": '{Provider}{ReferenceFolder}/{TagName}'}
										}
							}
	ValueSources = ['opc', 'reference']
	
	def initializeTagProperties(tagObject):
#		tagProperty = (tagObject)
		
#		logger.info('tag properties are - '+str(tagProperty))
#		logger.info(str(type(tagObject)))
		if (str(tagObject['name'])) not in [tag.name, 'SetupTags']:
			for ValueSource in ValueSources:
				try:
					logger.info('Keys we are trying to delete is - ' + str(valueSourceBindingMap[ValueSource].keys()[0]))
					tagObject.pop(str(valueSourceBindingMap[ValueSource].keys()[0]) )
				except:
					pass
				logger.info('Keys we have in dicts are - ' + str(tagObject.keys()))
#				if valueSourceBindingMap[ValueSource].keys()[0] not in tagObject.keys():
				tagObject[valueSourceBindingMap[ValueSource].keys()[0]] = valueSourceBindingMap[ValueSource].values()[0]
			
			logger.info(str(tagObject))
			system.tag.configure(str(tagObject['fullPath']).split(tagObject['name']), system.util.jsonEncode(tagObject), 'o')
			
			return
		
				
	if currentValue.value == True:
		logger = system.util.getLogger('UDTTestLogger')
		root = str(tagPath).split(tag.name)[0]
		logger.info('Setting Up Tags - ' + root)
		
		# Value source defines what JSON properties needs to be added to the Tag 
		
		tags = system.tag.browse(root, {"recursive":True}).results
		
		for tagtoInitialize in tags:
			logger.info(str(tagtoInitialize))
			logger.info('lets look at the type of the tag here ' + str(type(tagtoInitialize)))
			initializeTagProperties(tagtoInitialize)

Here are the logs: