Gateway Timer / Tag Change script:Lib funciton returns dict empty & Dataset tag not updating (works in Script Console)

In summary, the exact same code:

  • populates opcFolderCompareRows correctly and builds a non‑empty Dataset when run in the Script Console, and

  • writes successfully to the Dataset Memory tag [default]tgpna/OPC_Folder_Comparision there,

but in Gateway Timer / Tag Change scripts:

  • ICCP.DataValidation.compareFolder(...) appears to fail or return nothing so opcFolderCompareRows is empty or only contains the "ERROR" fallback rows, and

  • the Dataset written to the tag is therefore empty or just error rows, and the tag value does not change.

Function is as follows. It used OOPC browse
”” # locate 'To QSE' and From QSE folder on a server
def _findFolderNodeId(opcServer, targetName):
"""
Search the whole namespace starting at root for a folder (or object)
whose display name matches targetName.
Returns its nodeId or "" if not found.
"""
stack = [""] # start at root nodeId

while stack:
    nid = stack.pop()
    children = system.opc.browseServer(opcServer, nid)
    for ch in children:
        name   = ch.getDisplayName()
        childId = ch.getServerNodeId().getNodeId()
        etype  = str(ch.getElementType()).lower()

        if name == targetName:
            return childId

        # keep walking through Folder/Object nodes
        if "folder" in etype or "object" in etype:
            stack.append(childId)

return "" and another code   is 

import system

def compareFolder(serverA, serverB, folderName):
"""
Compare tag counts under a given folder (e.g. 'To QSE' or 'From QSE')
on two OPC UA servers. Continues even if one server is down.
"""

# Result structure returned to the caller (screen / other script)
result = {
    "ok": False,          # set True only if comparison completed
    "serverA": serverA,   # echo server names for display/logging
    "serverB": serverB,
    "folder": folderName, # which folder was compared
    "stateA": None,       # OPC connection state for serverA
    "stateB": None,       # OPC connection state for serverB
    "countA": 0,          # tag count on serverA under folderName
    "countB": 0,          # tag count on serverB under folderName
    "diff": 0,            # absolute difference between counts
    "sameCount": False,   # True if counts are equal
    "error": None         # error message text, if any
}

#  Safety check: servers exist 
servers = system.opc.getServers()
if serverA not in servers or serverB not in servers:
    result\["error"\] = "One or both OPC servers are not configured."
    return result

#  Get connection states (no early return) 
stateA = system.opc.getServerState(serverA)
stateB = system.opc.getServerState(serverB)
result\["stateA"\] = stateA
result\["stateB"\] = stateB

# Log connection warnings but continue
if stateA != "CONNECTED":
    result\["error"\] = "ServerA (%s) not CONNECTED: %s" % (serverA, stateA)
if stateB != "CONNECTED":
    msg = "ServerB (%s) not CONNECTED: %s" % (serverB, stateB)
    result\["error"\] = (result\["error"\] + " " + msg) if result\["error"\] else msg

#  Main comparison (tolerant per-server) 
nodeA = \_findFolderNodeId(serverA, folderName)
nodeB = \_findFolderNodeId(serverB, folderName)

# Note missing folders but continue counting
if not nodeA:
    msg = "Could not find '%s' on serverA (%s)." % (folderName, serverA)
    result\["error"\] = (result\["error"\] + " " + msg) if result\["error"\] else msg
if not nodeB:
    msg = "Could not find '%s' on serverB (%s)." % (folderName, serverB)
    result\["error"\] = (result\["error"\] + " " + msg) if result\["error"\] else msg

# Count tags under the folder on serverA, catching any browse errors.
if nodeA:
    try:
        countA = \_countVariables(serverA, nodeA)
    except Exception, e:
        msg = "Browse error on serverA (%s): %s" % (serverA, str(e))
        result\["error"\] = (result\["error"\] + " " + msg) if result\["error"\] else msg
        countA = 0
else:
    countA = 0

# Same for serverB.
if nodeB:
    try:
        countB = \_countVariables(serverB, nodeB)
    except Exception, e:
        msg = "Browse error on serverB (%s): %s" % (serverB, str(e))
        result\["error"\] = (result\["error"\] + " " + msg) if result\["error"\] else msg
        countB = 0
else:
    countB = 0

# Store counts safely as integers
result\["countA"\] = int(countA or 0)
result\["countB"\] = int(countB or 0)

# Calculate difference and equality flag
result\["diff"\] = abs(result\["countA"\] - result\["countB"\])
result\["sameCount"\] = (result\["diff"\] == 0)

# Always mark as completed
result\["ok"\] = True
return result. "“

Looking for guidance on what could cause this difference between console and gateway/tag‑event scope (project library scope, permissions, threading, or something else) and how to correctly call the ICCP library and write the Dataset tag from a Gateway Timer or Tag Change script.

Looks like you might have messed up the formatting a little bit when posting your code. See Wiki - how to post code on this forum. You can edit your post by clicking the pencil icon in the bottom right.

2 Likes