Writing Values to PLC UDT from Gateway

Hello all,

I'm working on a project where I will need to loop through our unit info database and input data into a UDT on the PLC so the Engineers can look through it and do different things with the tags on the PLC side of things. The database will be changing, so I will need to use some for loops to accomplish this and plan to just run this script every 15 minutes from the gateway. There is a max of 500 in the UDT; however, we only have 87 entries currently.

The way the tags are separated is "Unit_BOM_x/Unit_BOM_000/../..", where Unit_BOM_000 goes all the way to "Unit_BOM_499" and within each of these folders are 15 different named folders named "Base_Model", "Base_Platform", "Basket_Model", "Basket_Platform", "Cab_Model", "Cab_Platform", "Drive_Model", "Drive_Platform", "Model_Number", "Platform", "Spare1_Model", "Spare1_Platform", "Spare2_Model" and "Spare2_Platform" for different parts model/platform. Inside of those folders is DATA and LEN, I will only be using the DATA bit. The folders are in the same order and follow the same naming conventions for all 500 UDT entries.

I'm pretty stuck on this one, I'm not too experienced with writing to this many tags at once and spreading them out to other addresses. I'm lost on how I can sparse out the info to the specific tags for all 87 units we currently have. I am currently only going to be writing to "Basket_Model/DATA", "Basket_Platform/DATA", "Drive_Model/DATA" and "Drive_Platform/DATA". The rest is for expansion in the future.

I created a script to loop through all of the "Unit_BOM_xxx" records to create a path for the tag writing inside of the for loop but get stuck when having to dig further, as the other folders have different names, then I have to dig into that for the DATA bit.

def onScheduledEvent():
	for tagPath in range(500):
		title = "Unit_BOM_x/Unit_BOM_"
		digit = str(tagPath)
		title = title + digit

I guess I'm basically just asking for help on if anyone knows how I would proceed. I need to run a for loop on my query then disperse that data to these paths. For that loop, I have the following query:

def onScheduledEvent():
	for row in range(returnedDataset.getRowCount()):
		ModelNumber = returnedDataset.getValueAt(row, "ModelNum")
		DrivePlatform = returnedDataset.getValueAt(row, "DrivePlatform")
		BasketPlatform = returnedDataset.getValueAt(row, "BasketPlatform")

Any help or pointing in the right direction is highly appreciated. Thank you in advance.

To begin, you can use system.dataset.filterColumns(dataset, columns) (link to docs) to get a reduced dataset that has just the columns you want. Something like

	reduced_dataset = system.dataset.filterColumns(returnedDataset, ["ModelNum", "DrivePlatform", "BasketPlatform"]) #etc.

Then you can convert that to a flat list of values by looping over it as a pyDataset with list comprehension:

	reduced_pydataset = system.dataset.toPyDataset(reduced_dataset)
	#values_to_write = [ value for value in row for row in reduced_pydataset ]  wrong order to iterate
	values_to_write = [ value for row in reduced_pydataset for value in row ] 

Once you have that, you can use list comprehension to quickly generate the list of tag (or OPC) paths to write to.

	path_template = "Unit_BOM_x/Unit_BOM_{:03d}/{}/DATA"
	sub_items = ["Basket_Model", "Drive_Platform", "Basket_Platform"] #etc.
	tag_paths = [ path_template.format(unit_number, sub_item) for unit_number in range(88) for sub_item in sub_items ] #1 + max number

I used format to generate the leading zeros in the tag path.

Make sure your sub_items list correctly matches the list you used to filter your dataset in the same order. Then it's a matter of system.tag.writeAsync(tag_paths, values_to_write, callback) where callback is some function (defined by you) that will loop over the returned results and make sure all 87*3 tags were written correctly.

EDIT: Fixed list comprehension for future reference, see post below.

3 Likes

Wow Felipe, it's impressive how you made light work of this. I'm going to give it a whirl and see how things go. Thank you so much for explaining it in detail as I'm still learning every day. I really appreciate the comments so I can understand how it all works!

This is the error I'm getting:

image

You will need to post your script as you have it written. Essentially you have used a variable 'row' prior to assigning it a value.

1 Like

My bad, I mixed up the order of the comprehension in that line.
It's a little counter-intuitive (at least to me) but it should actually be

values_to_write = [ value for row in reduced_pydataset for value in row ] 

That way it generates row before it tries to iterate it.

It makes sense if you think of it as nesting the loops from left to right.

1 Like

Works flawlessly. I added a count query to replace that digit so that when it grows/shrinks it will automatically read those new edits. Thank you so much Felipe, you have no idea how helpful you were with this. This will help me a ton with future projects. I appreciate it!

3 Likes