UDT Quality for its children

Hi guys, I noticed that we can read a whole UDT instance (with its children) in a single system.tag.readBlocking() call, but the quality code is always good even though the quality of its children may not be.

Did anyone figure a good way to deal with that?

Within the UDT, I created an expression tag that was basically "isGood(childA) && isGood(childB) && ....", but it seems a bit fragile.

Show your code, please.

I wanted to check the quality of the children of the UDT since I wanted to add tags from other OPC sources, but right now they all come from Kepware.

Wec (aka. wind energy converter)

class Wec:
	def __init__(self, identifier, wind_speed_average, status, rbh_raw_value):
		self.identifier = identifier 
		self.wind_speed_average= wind_speed_average
		self.status = status
		self.rbh = Rbh(rbh_raw_value)

Initialize WECs

def initializeWECs():
	results = system.tag.browse('[default]Wec')
	paths = []
	for x in results:
		paths.append(str(x['fullPath']))
	qValues = system.tag.readBlocking(paths)
	wecList = []
	for qValue in qValues:
		value = qValue.value
		identifier = value['Identifier']
		goodQuality = qValue.quality.isGood() and value['IsGood']
		if not goodQuality: 
			continue
		wec = Wec(
			identifier, 
			value['WindSpeedAverage'], 
			value['Status'], 
			value['Ctrl']['Rbh']
		)
		wecList.append(wec)
	return wecList

UDT

{
  "name": "Wec",
  "parameters": {
    "ID": {
      "dataType": "Integer",
      "value": 0
    }
  },
  "tagType": "UdtType",
  "tags": [
    {
      "valueSource": "expr",
      "expression": "{ID}",
      "name": "Identifier",
      "tagType": "AtomicTag"
    },
    {
      "opcItemPath": {
        "bindType": "parameter",
        "binding": "nsu\u003dKEPServerEX;s\u003dEnercon.Main.Loc.Wec.Plant{ID}.Status.St"
      },
      "valueSource": "opc",
      "dataType": "Int4Array",
      "name": "Status",
      "tagType": "AtomicTag",
      "opcServer": "KEPServerEX_UA"
    },
    {
      "opcItemPath": {
        "bindType": "parameter",
        "binding": "nsu\u003dKEPServerEX;s\u003dEnercon.Main.Loc.Wec.Plant{ID}.Vwind"
      },
      "valueSource": "opc",
      "dataType": "Float4",
      "name": "WindSpeed",
      "tagType": "AtomicTag",
      "opcServer": "KEPServerEX_UA"
    },
    {
      "valueSource": "expr",
      "expression": "isGood({[.]Power})\r\n\u0026\u0026 isGood({[.]Status})\r\n\u0026\u0026 isGood({[.]WindSpeed})\r\n\u0026\u0026 isGood({[.]WindSpeedAverage})\r\n\u0026\u0026 isGood({[.]Ctrl/Rbh}) ",
      "dataType": "Boolean",
      "documentation": "Indicates whether all tags in this UDT has good quality or not.",
      "name": "IsGood",
      "tagType": "AtomicTag"
    },
    {
      "name": "Ctrl",
      "tagType": "Folder",
      "tags": [
        {
          "opcItemPath": {
            "bindType": "parameter",
            "binding": "nsu\u003dKEPServerEX;s\u003dEnercon.Main.Loc.Wec.Plant{ID}.Ctrl.SessionState"
          },
          "valueSource": "opc",
          "name": "SessionState",
          "tagType": "AtomicTag",
          "opcServer": "KEPServerEX_UA"
        },
        {
          "opcItemPath": {
            "bindType": "parameter",
            "binding": "nsu\u003dKEPServerEX;s\u003dEnercon.Main.Loc.Wec.Plant{ID}.Ctrl.SessionSubmit"
          },
          "valueSource": "opc",
          "dataType": "Int8Array",
          "name": "SessionSubmit",
          "tagType": "AtomicTag",
          "opcServer": "KEPServerEX_UA"
        },
        {
          "opcItemPath": {
            "bindType": "parameter",
            "binding": "nsu\u003dKEPServerEX;s\u003dEnercon.Main.Loc.Wec.Plant{ID}.Ctrl.Rbh"
          },
          "valueSource": "opc",
          "dataType": "Int8",
          "name": "Rbh",
          "tagType": "AtomicTag",
          "opcServer": "KEPServerEX_UA"
        },
        {
          "opcItemPath": {
            "bindType": "parameter",
            "binding": "nsu\u003dKEPServerEX;s\u003dEnercon.Main.Loc.Wec.Plant{ID}.Ctrl.SessionTimeOut"
          },
          "valueSource": "opc",
          "name": "SessionTimeOut",
          "tagType": "AtomicTag",
          "opcServer": "KEPServerEX_UA"
        },
        {
          "opcItemPath": {
            "bindType": "parameter",
            "binding": "nsu\u003dKEPServerEX;s\u003dEnercon.Main.Loc.Wec.Plant{ID}.Ctrl.SessionPubKey"
          },
          "valueSource": "opc",
          "dataType": "Int8",
          "name": "SessionPubKey",
          "tagType": "AtomicTag",
          "opcServer": "KEPServerEX_UA"
        },
        {
          "opcItemPath": {
            "bindType": "parameter",
            "binding": "nsu\u003dKEPServerEX;s\u003dEnercon.Main.Loc.Wec.Plant{ID}.Ctrl.SetRbh"
          },
          "valueSource": "opc",
          "dataType": "Int8Array",
          "name": "SetRbh",
          "tagType": "AtomicTag",
          "opcServer": "KEPServerEX_UA"
        },
        {
          "opcItemPath": {
            "bindType": "parameter",
            "binding": "nsu\u003dKEPServerEX;s\u003dEnercon.Main.Loc.Wec.Plant{ID}.Ctrl.SessionRequest"
          },
          "valueSource": "opc",
          "dataType": "Int8Array",
          "name": "SessionRequest",
          "tagType": "AtomicTag",
          "opcServer": "KEPServerEX_UA"
        }
      ]
    },
    {
      "valueSource": "memory",
      "dataType": "Float4",
      "name": "WindSpeedAverage",
      "value": 0,
      "tagType": "AtomicTag"
    },
    {
      "opcItemPath": {
        "bindType": "parameter",
        "binding": "nsu\u003dKEPServerEX;s\u003dEnercon.Main.Loc.Wec.Plant{ID}.P"
      },
      "valueSource": "opc",
      "name": "Power",
      "tagType": "AtomicTag",
      "opcServer": "KEPServerEX_UA"
    }
  ]
}

UDT Instances:

image

It seems to me that you need to recurse to get qualified values for the members of your instances.

{ And for performance sake, cache your recursive member lists--tag browsing is not something your code should be repeating all the time. }

3 Likes

"Reading" the base of a UDT or folder is actually an automatic read of the special computed jsonValues subproperty node. If you care about the inner qualities, you'll have to do a more specific read; the jsonValues node isn't designed to care about or return quality information.

3 Likes

Is jsonValues intended/designed for easily reading memory tags, where quality is not a factor?

As I understand things, it's used for some internal purpose to display the 'structure' of a tag quickly, while assuming everything within it is good quality. I think its original purpose had something to do with tag dropping in Perspective, but don't quote me on that :slight_smile:

1 Like