I'm attempting to count the number of tags that have a certain value

I'm using the follow 'onclick' script of a button But keep getting an error tagpath not defined

def runAction(self, event):
	
	# Specify the root tag path
    tagPath = "[default]NewFolder"

try:

    # Create a logger to log messages
    logger = system.util.getLogger("TagValueCounter")

    # Browse the tag folder
    browseResults = system.tag.browse(tagPath)

    # Initialize counter for tags with a defined value
    count = 0

    # Iterate over each tag and read its value
    for resultTag in browseResults.getResults():
        if resultTag['hasChildren']: 
            # Skip if it's a folder
            continue
        
        # Read the value of the tag
        tagValue = system.tag.readBlocking([str(resultTag['fullPath'])])[0].value
        
        # Check if the tag has a defined (non-null) value
        if tagValue is not None:
            count += 1

    # Print the count of tags with a defined value
    system.perspective.print("Tags with a defined value: " + str(count))
    # self.custom.count("Tags with a defined value: " + str(count))
    
except Exception as e:
    # Log any errors that occur
    logger.error("Error: " + str(e))

the tag path
image

Bits of your code aren't formatted as code so we're missing indentation, etc. See Wiki - how to post code on this forum and then you can edit your post to fix it.

thank you I will do that

def runAction(self, event):
	
	# Specify the root tag path
    tagPath = "[default]NewFolder"

try:

    # Create a logger to log messages
    logger = system.util.getLogger("TagValueCounter")

    # Browse the tag folder
    browseResults = system.tag.browse(tagPath)

    # Initialize counter for tags with a defined value
    count = 0

    # Iterate over each tag and read its value
    for resultTag in browseResults.getResults():
        
        if resultTag['hasChildren']: 
            # Skip if it's a folder
            continue
        
        # Read the value of the tag
        tagValue = system.tag.readBlocking([str(resultTag['fullPath'])])[0].value
        
        # Check if the tag has a defined (non-null) value
        if tagValue is not None:
            count += 1

    # Print the count of tags with a defined value
    system.perspective.print("Tags with a defined value: " + str(count))
    # self.custom.count("Tags with a defined value: " + str(count))
    
except Exception as e:
    # Log any errors that occur
    logger.error("Error: " + str(e))

Your entire try/except block is on the wrong indentation level and not part of the runAction function.

Taking a step back from the problems with your code - what are you actually attempting to accomplish with this script? Running recursive browsing functions in a Perspective button click is going to potentially put a lot of load on your gateway server for questionable benefit. What's the thing you're hoping to derive with this count of non-null values?

Also, just in case... Be very careful (or, more succinctly, don't use) LLMs like ChatGPT/etc to help you write Ignition specific scripts. They'll happily, confidently, lie to you about what system functions are available, what arguments they may take, what scope they're in, etc. LLMs can be useful for general algorithms and getting language syntax correct, but cannot be trusted with extremely specific domains like Ignition specific scripting functions or expressions.

Thank you for your comments. My Goal is I have set of tags that have a recipe value in them. I wanted to create a button that would count the tags that had a certain value. so the "operator" didn't have to count them up. The script would only run when they click on the button. Yes I did use CHATgpt to start the process. I'm very "GREEN" on coding with scripts. I thought it would be easier to do in ignition than writing in the plc.Thank you again for your comments and concerns.

Thank you Kevin.. I will look into that i'm very new to scripting.

Are you already displaying a list of those recipes ?
If you didn't implement that functionality, how would the operator count them ?

The term recipe is a bit loose basically I have about 120 tags that have 1,2,3 or 4 as a value. I just want to count all 1's ect and display that value. Currently the objects turn different colors on the screen. thats how they can tell how many of the "1" product and so on.

Well if they're already on the screen, that means you're already pulling the value. So you don't need to go through the tags themselves.

Are you displaying them in a table ?

1 Like

No I am not currently displaying them in a table. They are Label Components with dynamic links attached to color and text. I just want to count the tags using what there dynamic color value is. in the picture green is one product cyan is another

What's behind those labels ?
Did you hardcode individual tag bindings on each of them ?

yes I did hard code each one... it was my first week working with ignition
image

I plan on redoing it later maybe a table

Yes I suggest you use a table. You'll have to pull all the data at once, which will allow you to easily count how many of each values are in your data structure.

1 Like

Thank you I will start working on that ... Thank you again for your time and comments

It looks like this is all done in a coordinate View as well, when it's more suited to a flex View. You will have far better control and simpler setup with a flex.

If you're unfamiliar with flex containers, you would need to add flex containers within flex containers. e.g.

Where:

  • red = the root flex container itself
  • blues = 2 flex containers added into the root. Top = column, Bottom = column
  • magentas = 2 flex containers added into the bottom blue. Left = row, Right = row

I would be putting the legend colours on the single row.

2 Likes

Wait a bit before diving in.

There are differences between labels and tables. The main one is that to populate the table, you'll likely use a script and system.tag.readBlocking to read your tags in bulk. This is VERY different from the bindings you use there: the bindings update automatically, but a script won't.
There are ways to handle this.

You could make it refresh every x seconds for example, using now(x*1000) in an expression binding
Or you could use a template view for each tag. Make it take a tag path as parameter, and use it in an indirect binding, which will update automatically. Then you can use that template view with a table or a flex repeater, using a pre-generated list of tags to populate the table's row or the repeater's instances.

This kind of thing doesn't come naturally and it takes some time to see "the way", but we can help you kickstart your ignition experience.

3 Likes