recursivly showing all the tags in the views, modified the tags table

This commit is contained in:
Salijoghli 2025-09-22 14:13:13 +04:00
parent d43079042e
commit 82aece8bb3
34 changed files with 398 additions and 172 deletions

View File

@ -1567,6 +1567,75 @@
"results": {
"enabled": true
}
},
"selection": {
"data": [
{
"Description": {
"style": {
"classes": "Alarms-Styles/Diagnostic"
},
"value": "PS3_1_SIO1 - TEST"
},
"Device": {
"style": {
"classes": "Alarms-Styles/Diagnostic"
},
"value": "PS3_1_SIO1"
},
"Duration": {
"style": {
"classes": "Alarms-Styles/Diagnostic"
},
"value": "01:12:29"
},
"FullTag": {
"style": {
"classes": "Alarms-Styles/Diagnostic"
},
"value": "System/MCM01/IO_Block/SIO/PS3_1_SIO1/Alarm/twesrt"
},
"ID": {
"style": {
"classes": "Alarms-Styles/Diagnostic"
},
"value": 3
},
"Location": {
"style": {
"classes": "Alarms-Styles/Diagnostic"
},
"value": "MCM01"
},
"Priority": {
"style": {
"classes": "Alarms-Styles/Diagnostic"
},
"value": "Diagnostic"
},
"StartTimestamp": {
"style": {
"classes": "Alarms-Styles/Diagnostic"
},
"value": {
"$": [
"ts",
0,
1758293457803
],
"$ts": 1758289226000
}
},
"Tag": {
"style": {
"classes": "Alarms-Styles/Diagnostic"
},
"value": "PS3_1_SIO1.HMI.twesrt"
}
}
],
"selectedColumn": "Duration",
"selectedRow": 0
}
},
"type": "ia.display.table"
@ -3260,7 +3329,7 @@
"$": [
"ts",
192,
1758280365675
1758290858284
],
"$ts": 1755606669646
},
@ -3268,7 +3337,7 @@
"$": [
"ts",
192,
1758280365675
1758290858284
],
"$ts": 1755608469646
}
@ -4410,7 +4479,7 @@
"$": [
"ts",
192,
1758280365675
1758290858284
],
"$ts": 1755606669646
},
@ -4418,7 +4487,7 @@
"$": [
"ts",
192,
1758280365675
1758290858284
],
"$ts": 1755608469646
},

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

View File

@ -0,0 +1,81 @@
def deviceType(self, path, props):
try:
docked_view = "Docked-East-"
devices = []
tags = []
if "Conveyor" in path:
docked_view += "Conv"
devices = autStand.devices.build_device_table(self)
system.perspective.print(devices)
elif "VFD" in path:
docked_view += "VFD"
else:
docked_view += "Device"
tags = autStand.devices.getAllTags(self, props[0])
system.perspective.print(tags)
# return 1
return [docked_view, tags, devices]
except Exception as e:
import traceback
msg = "Error in deviceType: {}\n{}".format(str(e), traceback.format_exc())
system.perspective.print(msg)
# optionally: system.gui.errorBox(msg) # if running in Vision, not Perspective
return None
def handleTagHighlight(view, currentValue):
tag_priority = currentValue.value
# --- CASE 1: Remove all highlights by applying CLEAR class ---
if not tag_priority or str(tag_priority).upper() == "CLEAR":
for child in view.rootContainer.getChildren()[0].getChildren():
try:
child.props.style.classes = ""
except:
pass
return False
parts = str(tag_priority).split("||")
tag = parts[0]
splitedTag = tag.split("/")
deviceName = splitedTag[-1]
components = view.rootContainer.getChildren()[0].getChildren()
priority = parts[1]
foundMatch = False
# clear all highlights and apply new one when found
for child in components:
params = child.props.get("params", {})
tagProps = params.get("tagProps", {})
tagsList = list(tagProps)
if len(tagsList) == 0:
continue
child.props.style.classes = ""
tagPath = tagsList[0]
# system.perspective.print(tagPath)
if tag == tagPath:
child.props.style["classes"] = "Highlight/Pulse-" + priority
path = child.props.get("path")
# docked_view = deviceType(child)
docked_view = deviceType(view, path, tagProps)
# system.perspective.print(docked_view)
system.perspective.openDock(docked_view[0], params = {'tagProps':tagProps, 'tags': docked_view[1], 'devices':docked_view[2]})
# tags = autStand.devices.getAllTags(view, tagProps[0])
# system.perspective.openDock(docked_view, params={'tagProps': tagProps, 'tags': tags})
foundMatch = True
return foundMatch

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 710 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 763 B

View File

@ -1,6 +1,6 @@
{
"custom": {
"color": "#f9050d",
"color": "#C2C2C2",
"priority": "No Active Alarms"
},
"params": {

View File

@ -1,58 +0,0 @@
def deviceType(view):
path = view.props.get("path")
docked_view = "Docked-East-"
if "Conveyor" in path:
docked_view +="Conv"
elif "VFD" in path:
docked_view +="VFD"
else :
docked_view +="Device"
return docked_view
def handleTagHighlight(view, currentValue):
tag_priority = currentValue.value
# --- CASE 1: Remove all highlights by applying CLEAR class ---
if not tag_priority or str(tag_priority).upper() == "CLEAR":
for child in view.rootContainer.getChildren()[0].getChildren():
try:
child.props.style.classes = ""
except:
pass
return False
parts = str(tag_priority).split("||")
tag = parts[0]
splitedTag = tag.split("/")
deviceName = splitedTag[-1]
components = view.rootContainer.getChildren()[0].getChildren()
priority = parts[1]
foundMatch = False
# clear all highlights and apply new one when found
for child in components:
params = child.props.get("params", {})
tagProps = params.get("tagProps", {})
tagsList = list(tagProps)
if len(tagsList) == 0:
continue
child.props.style.classes = ""
tagPath = tagsList[0]
# system.perspective.print(tagPath)
if tag == tagPath:
child.props.style["classes"] = "Highlight/Pulse-" + priority
docked_view = deviceType(child)
system.perspective.openDock(docked_view, params={'tagProps': tagProps})
foundMatch = True
return foundMatch

View File

@ -3,7 +3,7 @@
"PLC": "MCM01",
"color": "#C2C2C2",
"showTags": true,
"state": "Actuated"
"state": "Closed"
},
"params": {
"devices": [],
@ -1225,7 +1225,10 @@
"sortable": true,
"strictWidth": false,
"style": {
"classes": ""
"classes": "",
"fontSize": "0.9vmin",
"whiteSpace": "normal",
"wordBreak": "break-all"
},
"toggleSwitch": {
"color": {
@ -1236,7 +1239,7 @@
"viewParams": {},
"viewPath": "",
"visible": true,
"width": 130
"width": 180
},
{
"align": "center",
@ -1317,7 +1320,10 @@
"sortable": true,
"strictWidth": false,
"style": {
"classes": ""
"classes": "",
"fontSize": "0.9vmin",
"whiteSpace": "normal",
"wordBreak": "break-all"
},
"toggleSwitch": {
"color": {
@ -1328,7 +1334,7 @@
"viewParams": {},
"viewPath": "",
"visible": true,
"width": 350
"width": 310
},
{
"align": "center",
@ -1409,7 +1415,8 @@
"sortable": true,
"strictWidth": false,
"style": {
"classes": ""
"classes": "",
"fontSize": "0.9vmin"
},
"toggleSwitch": {
"color": {
@ -1420,7 +1427,7 @@
"viewParams": {},
"viewPath": "",
"visible": true,
"width": 100
"width": ""
}
],
"pager": {
@ -1454,6 +1461,7 @@
"grow": 1
},
"props": {
"currentTabIndex": 3,
"menuType": "modern",
"tabSize": {
"width": 1000

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -167,12 +167,12 @@ def build_device_table(self):
def getAllTags(self, tagPath):
"""
Reads all tags under a UDT instance and returns a dataset.
Reads all tags under a UDT instance (recursively) and returns a dataset.
Args:
tagPath (str): Full path to the clicked device instance (e.g., System/MCM01/Photoeyes/TPE/PS3_1_TPE1)
fc_custom (str): Name of the FC custom property to determine the tag provider
tagPath (str): Full path to the clicked device instance
(e.g., System/MCM01/Photoeyes/TPE/PS3_1_TPE1)
Returns:
system.dataset: Dataset with columns ["Name", "OPC Path", "Value"]
"""
@ -180,34 +180,45 @@ def getAllTags(self, tagPath):
rows = []
try:
# Determine the tag provider
path = "[" + self.session.custom.fc + "_SCADA_TAG_PROVIDER]" + tagPath
providerPath = "[" + self.session.custom.fc + "_SCADA_TAG_PROVIDER]"
# Browse all child tags under this UDT instance
children = system.tag.browse(path, filter = {}).getResults()
for child in children:
tagType = str(child.get("tagType", ""))
name = str(child.get("name", ""))
fullPath = str(child.get("fullPath", ""))
# Remove provider if present
if fullPath.startswith("[") and "]" in fullPath:
fullPath = fullPath.split("]", 1)[1]
def browseRecursive(basePath, prefix=""):
children = system.tag.browse(providerPath + basePath, filter={}).getResults()
for child in children:
tagType = str(child.get("tagType", ""))
name = str(child.get("name", ""))
fullPath = str(child.get("fullPath", ""))
# Only include atomic tags, skip folders
if tagType == "AtomicTag":
value = None
try:
result = system.tag.readBlocking([fullPath])[0]
if result is not None and not result.isNull() and result.quality.isGood():
value = result.value
except:
value = "Unknown"
# Strip provider name
if fullPath.startswith("[") and "]" in fullPath:
fullPath = fullPath.split("]", 1)[1]
rows.append([name, fullPath, value])
if tagType == "AtomicTag":
value = None
try:
readPath = providerPath + fullPath
result = system.tag.readBlocking([readPath])[0]
if result.quality.isGood():
value = str(result.value)
else:
value = "Unknown"
except:
value = "Unknown"
# Use prefix/folder style path if inside folder
displayName = prefix + name if prefix else name
rows.append([displayName, fullPath, value])
elif tagType == "Folder":
# Dive deeper into folder
newPrefix = prefix + name + "/"
browseRecursive(basePath + "/" + name, prefix=newPrefix)
# Start recursion
browseRecursive(tagPath)
return system.dataset.toDataSet(headers, rows)
except Exception as e:
system.perspective.print("Error in getAllTags: {}".format(e))
return system.dataset.toDataSet(headers, [])
system.perspective.print("Error in getAllTags: {}".format(e))

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

View File

@ -10,8 +10,8 @@
"attributes": {
"lastModification": {
"actor": "admin",
"timestamp": "2025-09-19T12:36:20Z"
"timestamp": "2025-09-19T14:52:55Z"
},
"lastModificationSignature": "b2e342fbe4be98836829c596ad8705d49b652ed3b7d92ceffbd5959bf68bf8c5"
"lastModificationSignature": "426a85d902d87208ae4b9e1ece86b27662a69ec0f84ad8525cc6176457f2e505"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 44 KiB

View File

@ -1567,6 +1567,75 @@
"results": {
"enabled": true
}
},
"selection": {
"data": [
{
"Description": {
"style": {
"classes": "Alarms-Styles/Diagnostic"
},
"value": "PS3_1_SIO1 - TEST"
},
"Device": {
"style": {
"classes": "Alarms-Styles/Diagnostic"
},
"value": "PS3_1_SIO1"
},
"Duration": {
"style": {
"classes": "Alarms-Styles/Diagnostic"
},
"value": "01:12:29"
},
"FullTag": {
"style": {
"classes": "Alarms-Styles/Diagnostic"
},
"value": "System/MCM01/IO_Block/SIO/PS3_1_SIO1/Alarm/twesrt"
},
"ID": {
"style": {
"classes": "Alarms-Styles/Diagnostic"
},
"value": 3
},
"Location": {
"style": {
"classes": "Alarms-Styles/Diagnostic"
},
"value": "MCM01"
},
"Priority": {
"style": {
"classes": "Alarms-Styles/Diagnostic"
},
"value": "Diagnostic"
},
"StartTimestamp": {
"style": {
"classes": "Alarms-Styles/Diagnostic"
},
"value": {
"$": [
"ts",
0,
1758293457803
],
"$ts": 1758289226000
}
},
"Tag": {
"style": {
"classes": "Alarms-Styles/Diagnostic"
},
"value": "PS3_1_SIO1.HMI.twesrt"
}
}
],
"selectedColumn": "Duration",
"selectedRow": 0
}
},
"type": "ia.display.table"
@ -3260,7 +3329,7 @@
"$": [
"ts",
192,
1758280365675
1758290858284
],
"$ts": 1755606669646
},
@ -3268,7 +3337,7 @@
"$": [
"ts",
192,
1758280365675
1758290858284
],
"$ts": 1755608469646
}
@ -4410,7 +4479,7 @@
"$": [
"ts",
192,
1758280365675
1758290858284
],
"$ts": 1755606669646
},
@ -4418,7 +4487,7 @@
"$": [
"ts",
192,
1758280365675
1758290858284
],
"$ts": 1755608469646
},

View File

@ -10,8 +10,8 @@
"attributes": {
"lastModification": {
"actor": "admin",
"timestamp": "2025-09-19T13:41:00Z"
"timestamp": "2025-09-19T14:14:52Z"
},
"lastModificationSignature": "159bcf779d752460467d842af762f1f4a47cdc2f73efe60da26c4b885dd28702"
"lastModificationSignature": "182cc8b9fb64c597187e2e07de9667bc41a9398f6d5a3abeaf73bc1062d5dc13"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 58 KiB

View File

@ -10,8 +10,8 @@
"attributes": {
"lastModification": {
"actor": "admin",
"timestamp": "2025-09-19T13:58:13Z"
"timestamp": "2025-09-19T14:52:55Z"
},
"lastModificationSignature": "b67275b216883876b5da86e62e8434c6a7eb4f0d23a5ba286676c34465d88102"
"lastModificationSignature": "82fe10033dc0f7d34622625de96b56b94cdd37e8a748941e2989f86af46b003f"
}
}

View File

@ -4,7 +4,7 @@
"$": [
"ds",
192,
1758290292372
1758293575644
],
"$columns": [
{

View File

@ -10,8 +10,8 @@
"attributes": {
"lastModification": {
"actor": "admin",
"timestamp": "2025-09-16T13:36:34Z"
"timestamp": "2025-09-19T14:25:56Z"
},
"lastModificationSignature": "4b1237ac15b4a71b5aca7a85545cea02fd5bcbd3814669135b7d99c28c1a4c68"
"lastModificationSignature": "4a006674d6d86b950bd34d4dc9993b3dfe70377a954f0bcf9b632edb664fc92e"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 763 B

After

Width:  |  Height:  |  Size: 710 B

View File

@ -10,8 +10,8 @@
"attributes": {
"lastModification": {
"actor": "admin",
"timestamp": "2025-09-18T19:37:21Z"
"timestamp": "2025-09-19T14:26:19Z"
},
"lastModificationSignature": "a59741c6f4844901815e6d950b0dbdf1263034263340da919f0e85a01be19f7b"
"lastModificationSignature": "824eacbeea448afe5a876e2b7b4896da09a2fc68d7f1778abb2e5c05f2d4d1c5"
}
}

View File

@ -1,6 +1,6 @@
{
"custom": {
"color": "#f9050d",
"color": "#C2C2C2",
"priority": "No Active Alarms"
},
"params": {

View File

@ -10,8 +10,8 @@
"attributes": {
"lastModification": {
"actor": "admin",
"timestamp": "2025-09-12T08:57:39Z"
"timestamp": "2025-09-22T09:36:12Z"
},
"lastModificationSignature": "ceb13f6804a08c80f987c4ee866abe4c4961c8867da6993353eaa172e085ae22"
"lastModificationSignature": "4a36dafff395ff4abbb3f6ea103d133ce10be38fa32664a5b8410ce0dd8ad540"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -3,7 +3,7 @@
"PLC": "MCM01",
"color": "#C2C2C2",
"showTags": true,
"state": "Actuated"
"state": "Closed"
},
"params": {
"devices": [],
@ -1225,7 +1225,10 @@
"sortable": true,
"strictWidth": false,
"style": {
"classes": ""
"classes": "",
"fontSize": "0.9vmin",
"whiteSpace": "normal",
"wordBreak": "break-all"
},
"toggleSwitch": {
"color": {
@ -1236,7 +1239,7 @@
"viewParams": {},
"viewPath": "",
"visible": true,
"width": 130
"width": 180
},
{
"align": "center",
@ -1317,7 +1320,10 @@
"sortable": true,
"strictWidth": false,
"style": {
"classes": ""
"classes": "",
"fontSize": "0.9vmin",
"whiteSpace": "normal",
"wordBreak": "break-all"
},
"toggleSwitch": {
"color": {
@ -1328,7 +1334,7 @@
"viewParams": {},
"viewPath": "",
"visible": true,
"width": 350
"width": 310
},
{
"align": "center",
@ -1409,7 +1415,8 @@
"sortable": true,
"strictWidth": false,
"style": {
"classes": ""
"classes": "",
"fontSize": "0.9vmin"
},
"toggleSwitch": {
"color": {
@ -1420,7 +1427,7 @@
"viewParams": {},
"viewPath": "",
"visible": true,
"width": 100
"width": ""
}
],
"pager": {
@ -1454,6 +1461,7 @@
"grow": 1
},
"props": {
"currentTabIndex": 3,
"menuType": "modern",
"tabSize": {
"width": 1000

View File

@ -1,15 +1,32 @@
def deviceType(view):
path = view.props.get("path")
docked_view = "Docked-East-"
if "Conveyor" in path:
docked_view +="Conv"
elif "VFD" in path:
docked_view +="VFD"
else :
docked_view +="Device"
return docked_view
def deviceType(self, path, props):
try:
docked_view = "Docked-East-"
devices = []
tags = []
if "Conveyor" in path:
docked_view += "Conv"
devices = autStand.devices.build_device_table(self)
system.perspective.print(devices)
elif "VFD" in path:
docked_view += "VFD"
else:
docked_view += "Device"
tags = autStand.devices.getAllTags(self, props[0])
system.perspective.print(tags)
# return 1
return [docked_view, tags, devices]
except Exception as e:
import traceback
msg = "Error in deviceType: {}\n{}".format(str(e), traceback.format_exc())
system.perspective.print(msg)
# optionally: system.gui.errorBox(msg) # if running in Vision, not Perspective
return None
def handleTagHighlight(view, currentValue):
tag_priority = currentValue.value
@ -50,8 +67,14 @@ def handleTagHighlight(view, currentValue):
if tag == tagPath:
child.props.style["classes"] = "Highlight/Pulse-" + priority
docked_view = deviceType(child)
system.perspective.openDock(docked_view, params={'tagProps': tagProps})
path = child.props.get("path")
# docked_view = deviceType(child)
docked_view = deviceType(view, path, tagProps)
# system.perspective.print(docked_view)
system.perspective.openDock(docked_view[0], params = {'tagProps':tagProps, 'tags': docked_view[1], 'devices':docked_view[2]})
# tags = autStand.devices.getAllTags(view, tagProps[0])
# system.perspective.openDock(docked_view, params={'tagProps': tagProps, 'tags': tags})
foundMatch = True
return foundMatch

View File

@ -9,9 +9,9 @@
"attributes": {
"lastModification": {
"actor": "admin",
"timestamp": "2025-09-19T13:21:15Z"
"timestamp": "2025-09-19T14:43:02Z"
},
"hintScope": 2,
"lastModificationSignature": "717c54551cb487cf4325361e5e75e5db3a065f14656df7dc6ee5dca07eb0f544"
"lastModificationSignature": "9d58c365d8aba15c6e322fa153e168c440f81681d7ecc1e0e3405f21b64be363"
}
}

View File

@ -167,12 +167,12 @@ def build_device_table(self):
def getAllTags(self, tagPath):
"""
Reads all tags under a UDT instance and returns a dataset.
Reads all tags under a UDT instance (recursively) and returns a dataset.
Args:
tagPath (str): Full path to the clicked device instance (e.g., System/MCM01/Photoeyes/TPE/PS3_1_TPE1)
fc_custom (str): Name of the FC custom property to determine the tag provider
tagPath (str): Full path to the clicked device instance
(e.g., System/MCM01/Photoeyes/TPE/PS3_1_TPE1)
Returns:
system.dataset: Dataset with columns ["Name", "OPC Path", "Value"]
"""
@ -180,34 +180,45 @@ def getAllTags(self, tagPath):
rows = []
try:
# Determine the tag provider
path = "[" + self.session.custom.fc + "_SCADA_TAG_PROVIDER]" + tagPath
providerPath = "[" + self.session.custom.fc + "_SCADA_TAG_PROVIDER]"
# Browse all child tags under this UDT instance
children = system.tag.browse(path, filter = {}).getResults()
for child in children:
tagType = str(child.get("tagType", ""))
name = str(child.get("name", ""))
fullPath = str(child.get("fullPath", ""))
# Remove provider if present
if fullPath.startswith("[") and "]" in fullPath:
fullPath = fullPath.split("]", 1)[1]
def browseRecursive(basePath, prefix=""):
children = system.tag.browse(providerPath + basePath, filter={}).getResults()
for child in children:
tagType = str(child.get("tagType", ""))
name = str(child.get("name", ""))
fullPath = str(child.get("fullPath", ""))
# Only include atomic tags, skip folders
if tagType == "AtomicTag":
value = None
try:
result = system.tag.readBlocking([fullPath])[0]
if result is not None and not result.isNull() and result.quality.isGood():
value = result.value
except:
value = "Unknown"
# Strip provider name
if fullPath.startswith("[") and "]" in fullPath:
fullPath = fullPath.split("]", 1)[1]
rows.append([name, fullPath, value])
if tagType == "AtomicTag":
value = None
try:
readPath = providerPath + fullPath
result = system.tag.readBlocking([readPath])[0]
if result.quality.isGood():
value = str(result.value)
else:
value = "Unknown"
except:
value = "Unknown"
# Use prefix/folder style path if inside folder
displayName = prefix + name if prefix else name
rows.append([displayName, fullPath, value])
elif tagType == "Folder":
# Dive deeper into folder
newPrefix = prefix + name + "/"
browseRecursive(basePath + "/" + name, prefix=newPrefix)
# Start recursion
browseRecursive(tagPath)
return system.dataset.toDataSet(headers, rows)
except Exception as e:
system.perspective.print("Error in getAllTags: {}".format(e))
return system.dataset.toDataSet(headers, [])
system.perspective.print("Error in getAllTags: {}".format(e))

View File

@ -9,9 +9,9 @@
"attributes": {
"lastModification": {
"actor": "admin",
"timestamp": "2025-09-11T14:21:44Z"
"timestamp": "2025-09-22T10:07:38Z"
},
"hintScope": 2,
"lastModificationSignature": "ac100dce34bb5394c6ec164e067a535fc23d24c32e0c752058d22c189107f89f"
"lastModificationSignature": "71fab1ecf8f0a34c150bbd0e39819fb04f54cc9c1d343925f1b6d41c07383a4e"
}
}

View File

@ -36,3 +36,7 @@ Starting conversion: 20250919:12.08.01
Conversion finished. Elapsed time: 10 ms
Starting conversion: 20250919:14.45.44
Conversion finished. Elapsed time: 9 ms
Starting conversion: 20250920:12.20.22
Conversion finished. Elapsed time: 10 ms
Starting conversion: 20250922:11.54.29
Conversion finished. Elapsed time: 11 ms