Iterating selectively through Tag Folders to build Power Table

I have some scripting that iterates through the Gateway Devices folder hierarchy and populates a power table showing the Device Name, Enable Status and Connection Status. My Python skills are kindergarten level and it takes me hours of reading, trial and error, searches, etc. I marvel at the ease of some of your coding skills. To that end, the following two scripts accomplish the same thing. I started with the 1st one, but realize it wasn’t optimum due to the numerous read blocks.

So I developed the 2nd one, but I think my counter method is hokey, and there has to be a better way. I’m effectively going through the sub folders and picking out the three items I want and discarding the one I don’t (Description).

While you’re laughing at my feeble attempts, could someone please point me in a direction that looks more like someone who knows what they are doing? I find I learn easier by visual cues, and comparing what I do wrong to what should be done.

tags_in_folder = system.tag.browseTags('[System]/Gateway/Devices', recursive=True)
tag_data = []
for tag_info in tags_in_folder:
	if tag_info.isFolder():
		tag_enabled = tag_info.fullPath + '/Enabled'
		tag_name = tag_info.fullPath + '/Name'
		tag_status = tag_info.fullPath + '/Status'
		enabled_value = system.tag.readBlocking(tag_enabled)[0].value
		name_value = system.tag.readBlocking(tag_name)[0].value
		status_value = system.tag.readBlocking(tag_status)[0].value
		new_row = [name_value,enabled_value,status_value]
		tag_data.append(new_row)
headers = ["Name", "Enabled", "Status"]
dataset = system.dataset.toDataSet(headers, tag_data)
event.source.parent.getComponent('Group Device Status').getComponent('Power Table').data = dataset
tags_in_folder = system.tag.browseTags('[System]/Gateway/Devices', recursive=True)
tag_data = []
tags_path_list = []
for tag_info in tags_in_folder:
	if not tag_info.isFolder():
		tags_path_list.append(tag_info.fullPath)
tag_values = system.tag.readBlocking(tags_path_list)
z = 0
for i in range(len(tag_values)):
	if z == 2:
		name_value = tag_values[i].value
	elif z == 1:
		enabled_value = tag_values[i].value
	elif z == 3:
		status_value = tag_values[i].value
	z = z+1
	if z == 4:
		new_row = [name_value,enabled_value,status_value]
		print new_row
		tag_data.append(new_row)
		z = 0
headers = ["Name", "Enabled", "Status"]
dataset = system.dataset.toDataSet(headers, tag_data)
event.source.parent.getComponent('Group Device Status 1').getComponent('Power Table').data = dataset

I never remember this off the top of my head, but I'd highly recommend saving the snippet in this SO post into your project library somewhere you'll remember it:

Specifically:

def chunks(lst, n):
    """Yield successive n-sized chunks from lst."""
    for i in xrange(0, len(lst), n):
        yield lst[i:i + n]

I gave your code, that snippet, and some prompting to an LLM:

  1. List all devices in folder using browse (not recursive)
  2. Create a list of attributes you care about (name, enabled, status)
  3. Create a full list of tags to read, the cross product of devices * attributes
  4. Go through the list of return values, chunking into lists of size (len(attributes))
  5. Create a dataset out of the results, using the attribute names from the earlier list

And got this, which looks correct enough:

# Helper function to group items in a list into n-sized chunks
def chunks(lst, n):
 	"""Yield successive n-sized chunks from lst."""
 	for i in xrange(0, len(lst), n):
 		yield lst[i:i + n]

# 1. List all devices in the folder (non-recursively)
# We browse the path for folders, as each folder represents a device.
device_folder_path = '[System]/Gateway/Devices'
devices = system.tag.browse(path=device_folder_path, filter={'tagType': 'Folder'}).getResults()

# 2. Define the attributes (tag names) we care about
# This list will also serve as our dataset headers.
headers = ["name", "enabled", "status"]

# 3. Create the full list of tag paths to read
# This builds the cross product of all devices and their desired attributes.
tag_paths_to_read = []
for device in devices:
	device_path = str(device.getFullPath())
	for attribute in headers:
		tag_paths_to_read.append(device_path + '/' + attribute)

# Read all tag values in a single efficient, blocking call
qualified_values = system.tag.readBlocking(tag_paths_to_read)

# Extract just the raw .value from each QualifiedValue object
values = [qv.value for qv in qualified_values]

# 4. Chunk the flat list of values into rows for our dataset
# The chunk size is the number of attributes we read per device.
data_rows = list(chunks(values, len(headers)))

# 5. Create a dataset from the headers and the chunked data
dataset = system.dataset.toDataSet(headers, data_rows)

# Assign the new dataset to the target Power Table component
event.source.parent.getComponent('Group Device Status 1').getComponent('Power Table').data = dataset

Thanks!

The dictionary path is the wrong syntax

for device in devices: 	device_path = str(device.getFullPath())

This worked

for device in devices:
	device_path = str(device['FullPath'])

I’m going to study this. I see where I was close, and where I could have done better. I just couldn’t figure out the filtering by the values I needed, using the attribute in headers segment.