diff --git a/.resources/0283d219b9246afe93f6389510e7788d493206aff1376c0652d5d7ffdc0fb1bb b/.resources/0283d219b9246afe93f6389510e7788d493206aff1376c0652d5d7ffdc0fb1bb new file mode 100644 index 00000000..ca12e795 Binary files /dev/null and b/.resources/0283d219b9246afe93f6389510e7788d493206aff1376c0652d5d7ffdc0fb1bb differ diff --git a/.resources/0c093a3c6c118c52934f3f45adf68b7d23404a16aaa35f7ed8cf3aedbc15d8f5 b/.resources/0c093a3c6c118c52934f3f45adf68b7d23404a16aaa35f7ed8cf3aedbc15d8f5 deleted file mode 100644 index 90573ef3..00000000 --- a/.resources/0c093a3c6c118c52934f3f45adf68b7d23404a16aaa35f7ed8cf3aedbc15d8f5 +++ /dev/null @@ -1,308 +0,0 @@ -import os, json, sys - -global_device_mapping = {} - -def build_device_mapping(full_tag_path): - """ - Builds global_device_mapping for devices that: - - Belong to the same PLC (index 1) - - Are children of the clicked device (start with clicked_name + "_") - """ - global global_device_mapping - global_device_mapping.clear() - - - - try: - # Parse PLC and clicked device - path_parts = full_tag_path.split("/") - plc_name = path_parts[1] if len(path_parts) > 1 else path_parts[0] - clicked_name = path_parts[-1] if len(path_parts) > 0 else "" - if "_VFD" in clicked_name: - idx = clicked_name.find("_VFD") - if idx != -1: - clicked_name = clicked_name[:idx] - - project_name = system.util.getProjectName() - base_path = ( - os.getcwd().replace("\\", "/") - + "/data/projects/" - + project_name - + "/com.inductiveautomation.perspective/Views/autStand/Detailed_Views/MCM-Views" - ) - - if not os.path.exists(base_path): - system.perspective.print("Path not found: " + base_path) - return {} - - # loop through all view folders - for view_folder in os.listdir(base_path): - json_file = os.path.join(base_path, view_folder, "view.json") - if not os.path.isfile(json_file): - continue - - try: - with open(json_file, "r") as fh: - view_json = json.load(fh) - except Exception: - continue - - # go one level deeper: root -> children[0] (coordinateContainer) -> its children - root_children = (view_json.get("root") or {}).get("children") or [] - if not root_children: - continue - - container = root_children[0] - children = container.get("children") or [] - - for child in children: - props = child.get("props") or {} - params = props.get("params") or {} - tag_props = params.get("tagProps") - - if isinstance(tag_props, list) and len(tag_props) > 0: - tag_prop = str(tag_props[0]) - parts = tag_prop.split("/") - - if len(parts) > 1 and parts[1] == plc_name: - - dev_name = parts[-1] - if len(parts) > 3 and parts[-2] == clicked_name: - dev_name = clicked_name + "_" + parts[-1] - system.perspective.print(dev_name) - - # ONLY include devices that are children of clicked_name - else: - dev_name = parts[-1] - prefix = clicked_name + "_" - - if dev_name.startswith(prefix) or (len(parts) > 3 and parts[-2] == clicked_name): - global_device_mapping[dev_name] = { - "tagPath": tag_prop, - "zone": view_folder - } - - return global_device_mapping - - except Exception as e: - whid = "unknown" - try: - whid = system.tag.readBlocking("Configuration/FC")[0].value - except: - pass - logger = system.util.getLogger("%s-build_device_mapping" % whid) - exc_type, exc_obj, tb = sys.exc_info() - logger.error("Error at line %s: %s" % (tb.tb_lineno, exc_obj)) - return {} - -def build_device_table(self): - """ - Converts global_device_mapping into a list of dictionaries: - Keys: Device, Status - Reads each tag value, falls back to 'Unknown' if error/null. - """ - rows = [] - state_mappings = { - 0: "Closed", - 1: "Actuated", - 2: "Communication Faulted", - 3: "Conveyor Running In Maintenance Mode", - 4: "Disabled", - 5: "Disconnected", - 6: "Stopped", - 7: "Enabled Not Running", - 8: "Encoder Fault", - 9: "Energy Management", - 10: "ESTOP Was Actuated", - 11: "EStopped", - 12: "EStopped Locally", - 13: "Extended Faulted", - 14: "Full", - 15: "Gaylord Start Pressed", - 16: "Jam Fault", - 17: "Jammed", - 18: "Loading Allowed", - 19: "Loading Not Allowed", - 20: "Low Air Pressure Fault Was Present", - 21: "Maintenance Mode", - 22: "Conveyor Stopped In Maintenance Mode", - 23: "Motor Faulted", - 24: "Motor Was Faulted", - 25: "Normal", - 26: "Off Inactive", - 27: "Open", - 28: "PLC Ready To Run", - 29: "Package Release Pressed", - 30: "Power Branch Was Faulted", - 31: "Pressed", - 32: "Ready To Receive", - 33: "Running", - 34: "Started", - 35: "Stopped", - 36: "System Started", - 37: "Unknown", - 38: "VFD Fault", - 39: "Conveyor Running In Power Saving Mode", - 40: "Conveyor Jogging In Maintenance Mode", - 41: "VFD Reset Required", - 42: "Jam Reset Push Button Pressed", - 43: "Start Push Button Pressed", - 44: "Stop Push Button Pressed", - 45: "No Container", - 46: "Ready To Be Enabled", - 47: "Half Full", - 48: "Enabled", - 49: "Tipper Faulted" - } - - try: - for dev_name, info in global_device_mapping.items(): - tagPath = info.get("tagPath", "") - status_value = "" - provider = "[" + self.session.custom.fc + "_SCADA_TAG_PROVIDER]" - path = provider + tagPath + "/STATE" - - if tagPath: - try: - result = system.tag.readBlocking([path])[0] - status_value = state_mappings.get(result.value, "Unknown") - except: - status_value = "Unknown" - - # Append as dictionary - rows.append({ - 'Device': dev_name, - 'Status': status_value - }) - - return rows - - except Exception as e: - system.perspective.print("Error building device table: %s" % e) - return [] # Return empty list on error - - -def getAllTags(self, tagPath, section="all"): - """ - Reads all tags under a UDT instance (recursively) and returns a list of dictionaries. - - Supports: - - VFD (Drive folder) - - Conveyor (skips Drive) - - Chute (root + PE/PRX/EN tags) - - Single Photoeyes (PE1/PE2) - - Single Prox Sensors (PRX1/PRX2) - - Enable buttons (EN_Color, EN_State, EN_Priority) - - Tracking Photoeyes (TPE, handles both folder- and struct-style UDTs) - """ - - rows = [] - - try: - providerPath = "[" + self.session.custom.fc + "_SCADA_TAG_PROVIDER]" - driveFolderName = "Drive" - - - # === Utility: read a single atomic tag === - def readSingleTag(path, prefix=""): - try: - result = system.tag.readBlocking([providerPath + path])[0] - value = str(result.value) if result.quality.isGood() else "Unknown" - except: - value = "Unknown" - - displayName = prefix + path.split("/")[-1] if prefix else path.split("/")[-1] - rows.append({ - "Name": displayName, - "OPC Path": path, - "Value": value - }) - - # === Utility: recursive browse === - def browseRecursive(basePath, prefix=""): - children = system.tag.browse(providerPath + basePath).getResults() - - for child in children: - tagType = str(child.get("tagType", "")) - name = str(child.get("name", "")) - fullPath = str(child.get("fullPath", "")) - - if fullPath.startswith("[") and "]" in fullPath: - fullPath = fullPath.split("]", 1)[1] - - # --- Conveyor filter (skip Drive folder) --- - if section == "conveyor" and name == driveFolderName: - continue - - if tagType == "Folder": - newPrefix = prefix + name + "/" if prefix else name + "/" - browseRecursive(basePath + "/" + name, newPrefix) - elif tagType == "AtomicTag": - readSingleTag(fullPath, prefix) - - # === MAIN ENTRY POINT === - if section == "vfd": - # Browse only inside Drive folder - drivePath = tagPath + "/" + driveFolderName - browseRecursive(drivePath) - - elif tagPath.upper().endswith("/EN"): - # --- Handle flat EN_ tags --- - parentPath = "/".join(tagPath.split("/")[:-1]) - children = system.tag.browse(providerPath + parentPath).getResults() - - for child in children: - tagType = str(child.get("tagType", "")) - name = str(child.get("name", "")) - if tagType == "AtomicTag" and name.upper().startswith("EN_"): - fullPath = str(child.get("fullPath", "")) - if fullPath.startswith("[") and "]" in fullPath: - fullPath = fullPath.split("]", 1)[1] - readSingleTag(fullPath) - - elif tagPath.upper().endswith(("PE1", "PE2", "PRX1", "PRX2")) and "/TPE/" not in tagPath.upper(): - # --- Single sensors --- - readSingleTag(tagPath) - - else: - # --- Default path --- - browseResult = system.tag.browse(providerPath + tagPath).getResults() - - if not browseResult: - # Possibly a struct-style UDT (like some TPEs) - system.perspective.print("Empty browse for {}, checking struct value...".format(tagPath)) - try: - result = system.tag.readBlocking([providerPath + tagPath])[0] - value = result.value - - # If we got a STRUCT, expand it into sub-rows - if isinstance(value, dict): - system.perspective.print("Detected STRUCT value, expanding {}".format(tagPath)) - - def flattenStruct(struct, base=""): - for k, v in struct.items(): - newName = base + "/" + k if base else k - if isinstance(v, dict): - flattenStruct(v, newName) - else: - rows.append({ - "Name": newName, - "OPC Path": tagPath + "/" + newName, - "Value": str(v) - }) - - flattenStruct(value) - else: - # Not a struct, just read it normally - readSingleTag(tagPath) - except Exception as ex: - system.perspective.print("Fallback read failed for {}: {}".format(tagPath, ex)) - else: - # Normal case — browse folder/UDT structure - browseRecursive(tagPath) - - return rows - - except Exception as e: - system.perspective.print("Error in getAllTags: {}".format(e)) - return [] diff --git a/.resources/d5fe08d6896ad1310d3e7b2327ef9c6e356a006f5740c9c03190b3e2819a5e05 b/.resources/0f947b6ff7329053a6b872cab7e02de58fab1f98d61baea268d6f7fa8cca8895 similarity index 99% rename from .resources/d5fe08d6896ad1310d3e7b2327ef9c6e356a006f5740c9c03190b3e2819a5e05 rename to .resources/0f947b6ff7329053a6b872cab7e02de58fab1f98d61baea268d6f7fa8cca8895 index 57218d35..5eef58ec 100644 --- a/.resources/d5fe08d6896ad1310d3e7b2327ef9c6e356a006f5740c9c03190b3e2819a5e05 +++ b/.resources/0f947b6ff7329053a6b872cab7e02de58fab1f98d61baea268d6f7fa8cca8895 @@ -3,7 +3,7 @@ "color": "#000000", "deviceName": "S03_1_JR1", "priority": "No Active Alarms", - "state": "Offline" + "state": "Actuated" }, "params": { "demoColor": -1, diff --git a/.resources/3319d3ab91e51d10a0c98703f7f56be4dbab61eabb9d7d5facd1381f9ec436c8 b/.resources/1207383d3d26b32fc16ffb6a25abaab44d7b5d67a8e9e5bca5c9aaa34da8550e similarity index 86% rename from .resources/3319d3ab91e51d10a0c98703f7f56be4dbab61eabb9d7d5facd1381f9ec436c8 rename to .resources/1207383d3d26b32fc16ffb6a25abaab44d7b5d67a8e9e5bca5c9aaa34da8550e index 8ec9703f..25165cbe 100644 --- a/.resources/3319d3ab91e51d10a0c98703f7f56be4dbab61eabb9d7d5facd1381f9ec436c8 +++ b/.resources/1207383d3d26b32fc16ffb6a25abaab44d7b5d67a8e9e5bca5c9aaa34da8550e @@ -71,232 +71,6 @@ "persistent": true }, "custom.state": { - "binding": { - "config": { - "fallbackDelay": 2.5, - "mode": "indirect", - "references": { - "0": "{view.params.tagProps[0]}", - "fc": "{session.custom.fc}" - }, - "tagPath": "[{fc}_SCADA_TAG_PROVIDER]{0}/State" - }, - "transforms": [ - { - "expression": "coalesce({value},-1)", - "type": "expression" - }, - { - "fallback": "Offline", - "inputType": "scalar", - "mappings": [ - { - "input": 0, - "output": "Closed" - }, - { - "input": 1, - "output": "Actuated" - }, - { - "input": 2, - "output": "Communication Faulted" - }, - { - "input": 3, - "output": "Conveyor Running In Maintenance Mode" - }, - { - "input": 4, - "output": "Disabled" - }, - { - "input": 5, - "output": "Disconnected" - }, - { - "input": 6, - "output": "Stopped" - }, - { - "input": 7, - "output": "Enabled Not Running" - }, - { - "input": 8, - "output": "Encoder Fault" - }, - { - "input": 9, - "output": "Energy Management" - }, - { - "input": 10, - "output": "ESTOP Was Actuated" - }, - { - "input": 11, - "output": "EStopped" - }, - { - "input": 12, - "output": "EStopped Locally" - }, - { - "input": 13, - "output": "Extended Faulted" - }, - { - "input": 14, - "output": "Full" - }, - { - "input": 15, - "output": "Gaylord Start Pressed" - }, - { - "input": 16, - "output": "Jam Fault" - }, - { - "input": 17, - "output": "Jammed" - }, - { - "input": 18, - "output": "Loading Allowed" - }, - { - "input": 19, - "output": "Loading Not Allowed" - }, - { - "input": 20, - "output": "Low Air Pressure Fault Was Present" - }, - { - "input": 21, - "output": "Maintenance Mode" - }, - { - "input": 22, - "output": "Conveyor Stopped In Maintenance Mode" - }, - { - "input": 23, - "output": "Motor Faulted" - }, - { - "input": 24, - "output": "Motor Was Faulted" - }, - { - "input": 25, - "output": "Normal" - }, - { - "input": 26, - "output": "Off Inactive" - }, - { - "input": 27, - "output": "Open" - }, - { - "input": 28, - "output": "PLC Ready To Run" - }, - { - "input": 29, - "output": "Package Release Pressed" - }, - { - "input": 30, - "output": "Power Branch Was Faulted" - }, - { - "input": 31, - "output": "Pressed" - }, - { - "input": 32, - "output": "Ready To Receive" - }, - { - "input": 33, - "output": "Running" - }, - { - "input": 34, - "output": "Started" - }, - { - "input": 35, - "output": "Stopped" - }, - { - "input": 36, - "output": "System Started" - }, - { - "input": 37, - "output": "Unknown" - }, - { - "input": 38, - "output": "VFD Fault" - }, - { - "input": 39, - "output": "Conveyor Running In Power Saving Mode" - }, - { - "input": 40, - "output": "Conveyor Jogging In Maintenance Mode" - }, - { - "input": 41, - "output": "VFD Reset Required" - }, - { - "input": 42, - "output": "Jam Reset Push Button Pressed" - }, - { - "input": 43, - "output": "Start Push Button Pressed" - }, - { - "input": 44, - "output": "Stop Push Button Pressed" - }, - { - "input": 45, - "output": "No Container" - }, - { - "input": 46, - "output": "Ready To Be Enabled" - }, - { - "input": 47, - "output": "Half Full" - }, - { - "input": 48, - "output": "Enabled" - }, - { - "input": 49, - "output": "Tipper Faulted" - } - ], - "outputType": "scalar", - "type": "map" - } - ], - "type": "tag" - }, "persistent": true }, "custom.view": { @@ -307,6 +81,10 @@ "persistent": true }, "params.tagProps": { + "onChange": { + "enabled": null, + "script": "\ttagPath \u003d currentValue.value[0].value #I know this looks ugly\t\t\t\n\tstatus \u003d autStand.devices.get_single_device_status(self, tagPath)\n\tself.view.custom.state \u003d status\n\n" + }, "paramDirection": "input", "persistent": true }, diff --git a/.resources/84d05ea0f351c0cdb138f6ec5a365afaaf21ba95481d3e19fbb453d4ecc70772 b/.resources/121d4eb22bae0dbb6ea4a1600919499c33b8cad5a04a06e92339cf9ba9a5fb71 similarity index 98% rename from .resources/84d05ea0f351c0cdb138f6ec5a365afaaf21ba95481d3e19fbb453d4ecc70772 rename to .resources/121d4eb22bae0dbb6ea4a1600919499c33b8cad5a04a06e92339cf9ba9a5fb71 index 5db94a0f..45ad6482 100644 --- a/.resources/84d05ea0f351c0cdb138f6ec5a365afaaf21ba95481d3e19fbb453d4ecc70772 +++ b/.resources/121d4eb22bae0dbb6ea4a1600919499c33b8cad5a04a06e92339cf9ba9a5fb71 @@ -594,7 +594,7 @@ "dom": { "onClick": { "config": { - "script": "\t#create devices and tags lists for the conveyor\n\tprops \u003d self.view.params.tagProps[0]\n\tautStand.devices.build_device_mapping(props)\n\tdevice_table_dataset \u003d autStand.devices.build_device_table(self)\n\ttags_table_dataset \u003d autStand.devices.getAllTags(self, props)\n\tsystem.perspective.openDock(\u0027Docked-East-Conv\u0027,params\u003d{\u0027tagProps\u0027:self.view.params.tagProps, \"devices\": device_table_dataset, \"tags\":tags_table_dataset})" + "script": "\t#create devices and tags lists for the conveyor\n\tprops \u003d self.view.params.tagProps[0]\n\tautStand.devices.build_device_mapping(props)\n\tdevice_table_dataset \u003d autStand.devices.build_device_table(self)\n\ttags_table_dataset \u003d autStand.devices.getAllTags(self, props, section \u003d \"conveyor\")\n\tsystem.perspective.openDock(\u0027Docked-East-Conv\u0027,params\u003d{\u0027tagProps\u0027:self.view.params.tagProps, \"devices\": device_table_dataset, \"tags\":tags_table_dataset})" }, "scope": "G", "type": "script" diff --git a/.resources/b31a70ba02543ec33bf35455cd5e004ae4ce06b3e477e8170f43030c40d70ba9 b/.resources/1cf33ac11162fda9ac2c0c29400165a6db405ae4f2921ce266b58ee6e1472dbc similarity index 99% rename from .resources/b31a70ba02543ec33bf35455cd5e004ae4ce06b3e477e8170f43030c40d70ba9 rename to .resources/1cf33ac11162fda9ac2c0c29400165a6db405ae4f2921ce266b58ee6e1472dbc index b48fea96..33f80aba 100644 --- a/.resources/b31a70ba02543ec33bf35455cd5e004ae4ce06b3e477e8170f43030c40d70ba9 +++ b/.resources/1cf33ac11162fda9ac2c0c29400165a6db405ae4f2921ce266b58ee6e1472dbc @@ -443,7 +443,7 @@ "basis": "32px" }, "props": { - "text": 20, + "text": 6, "textStyle": { "fontSize": 10, "textAlign": "center" @@ -472,7 +472,7 @@ "basis": "32px" }, "props": { - "text": 2, + "text": 1, "textStyle": { "fontSize": 10, "textAlign": "center" @@ -501,7 +501,7 @@ "basis": "32px" }, "props": { - "text": 5, + "text": 2, "textStyle": { "fontSize": 10, "textAlign": "center" @@ -559,7 +559,7 @@ "basis": "32px" }, "props": { - "text": 27, + "text": 9, "textStyle": { "fontSize": 10, "textAlign": "center" @@ -625,9 +625,9 @@ "counts": { "Critical": 0, "Diagnostic": 0, - "High": 20, - "Low": 5, - "Medium": 2 + "High": 6, + "Low": 2, + "Medium": 1 } }, "events": { diff --git a/.resources/21b5ec22a3500997b5c990bc734ad5f8a4cb01c55ec43cc1cd34248e4829eed8 b/.resources/21b5ec22a3500997b5c990bc734ad5f8a4cb01c55ec43cc1cd34248e4829eed8 new file mode 100644 index 00000000..0dc9abde Binary files /dev/null and b/.resources/21b5ec22a3500997b5c990bc734ad5f8a4cb01c55ec43cc1cd34248e4829eed8 differ diff --git a/.resources/367c2cdeea6523d0d3c77f6c39d3309dbb178f790ca57f402f46e0bcfae1a3a6 b/.resources/367c2cdeea6523d0d3c77f6c39d3309dbb178f790ca57f402f46e0bcfae1a3a6 new file mode 100644 index 00000000..e5d311d4 Binary files /dev/null and b/.resources/367c2cdeea6523d0d3c77f6c39d3309dbb178f790ca57f402f46e0bcfae1a3a6 differ diff --git a/.resources/3bb422ea6fd6c8ae3d0d45648ce7cad719f29cc23b3109efff99e7ff022297d6 b/.resources/3bb422ea6fd6c8ae3d0d45648ce7cad719f29cc23b3109efff99e7ff022297d6 new file mode 100644 index 00000000..b5a2c4ff --- /dev/null +++ b/.resources/3bb422ea6fd6c8ae3d0d45648ce7cad719f29cc23b3109efff99e7ff022297d6 @@ -0,0 +1,77 @@ +{ + "custom": {}, + "params": { + "text": "Provide for a sufficient cooling of the device." + }, + "propConfig": { + "params.text": { + "paramDirection": "input", + "persistent": true + } + }, + "props": { + "defaultSize": { + "height": 50, + "width": 300 + } + }, + "root": { + "children": [ + { + "meta": { + "name": "Icon" + }, + "position": { + "basis": "20px", + "shrink": 0 + }, + "props": { + "path": "material/brightness_1", + "style": { + "color": "black", + "marginLeft": 4, + "marginTop": 4 + } + }, + "type": "ia.display.icon" + }, + { + "meta": { + "name": "Label" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "props.text": { + "binding": { + "config": { + "path": "view.params.text" + }, + "type": "property" + } + } + }, + "props": { + "textStyle": { + "color": "black", + "fontSize": "18px" + } + }, + "type": "ia.display.label" + } + ], + "meta": { + "name": "root" + }, + "props": { + "alignContent": "center", + "alignItems": "flex-start", + "justify": "space-evenly", + "style": { + "gap": 7 + } + }, + "type": "ia.container.flex" + } +} \ No newline at end of file diff --git a/.resources/b61ee0e449411cb215d70f10b09b762f266bcbb1caa34481218fbf6c43da3258 b/.resources/3e349c69f39cb7ee6e99f6da0f8a40c0e8e7ab80da910d2d5e37e916f06dd2aa similarity index 99% rename from .resources/b61ee0e449411cb215d70f10b09b762f266bcbb1caa34481218fbf6c43da3258 rename to .resources/3e349c69f39cb7ee6e99f6da0f8a40c0e8e7ab80da910d2d5e37e916f06dd2aa index a756e355..19050170 100644 --- a/.resources/b61ee0e449411cb215d70f10b09b762f266bcbb1caa34481218fbf6c43da3258 +++ b/.resources/3e349c69f39cb7ee6e99f6da0f8a40c0e8e7ab80da910d2d5e37e916f06dd2aa @@ -3,7 +3,7 @@ "color": "#000000", "deviceName": "S03_CH115_EN", "priority": "No Active Alarms", - "state": "Offline" + "state": "Closed" }, "params": { "demoColor": -1, diff --git a/.resources/9d6363eca8180a957bf40753ca7580d20c8bbb01c3ccbc22d828f6b4833b9171 b/.resources/5ab7dd24323a45bff53f8edec76d6e999948a8dfc18410847f6876dc85cccedd similarity index 99% rename from .resources/9d6363eca8180a957bf40753ca7580d20c8bbb01c3ccbc22d828f6b4833b9171 rename to .resources/5ab7dd24323a45bff53f8edec76d6e999948a8dfc18410847f6876dc85cccedd index 27de9c16..ec71ac13 100644 --- a/.resources/9d6363eca8180a957bf40753ca7580d20c8bbb01c3ccbc22d828f6b4833b9171 +++ b/.resources/5ab7dd24323a45bff53f8edec76d6e999948a8dfc18410847f6876dc85cccedd @@ -3,7 +3,7 @@ "beacon": 0, "flashingColor": "#808080", "solidColor": "#FF8C00", - "state": "Offline" + "state": "OFF" }, "params": { "demoColor": "", diff --git a/.resources/a64014ead80ed43f3f1aef40e81f369d1c623ac217981d4949bae9fd8a8e3ad0 b/.resources/5ae25b8cc682cc46388bbc12f4e0dd53286068f61d15fca26bf5bdde93800af6 similarity index 99% rename from .resources/a64014ead80ed43f3f1aef40e81f369d1c623ac217981d4949bae9fd8a8e3ad0 rename to .resources/5ae25b8cc682cc46388bbc12f4e0dd53286068f61d15fca26bf5bdde93800af6 index 2f431a15..2dbbe3da 100644 --- a/.resources/a64014ead80ed43f3f1aef40e81f369d1c623ac217981d4949bae9fd8a8e3ad0 +++ b/.resources/5ae25b8cc682cc46388bbc12f4e0dd53286068f61d15fca26bf5bdde93800af6 @@ -3,7 +3,7 @@ "PLC": "MCM01", "color": "#C2C2C2", "showTags": true, - "state": "Offline" + "state": "Closed" }, "params": { "devices": [], diff --git a/.resources/2a0d11f91d3434e3998c9168a085bc1d87e698b06e082a8e2f76f9b99305c8a6 b/.resources/5be9bf5bf5b73a329337536ee97e9887808e84e352022a00393af671ab69d9ba similarity index 99% rename from .resources/2a0d11f91d3434e3998c9168a085bc1d87e698b06e082a8e2f76f9b99305c8a6 rename to .resources/5be9bf5bf5b73a329337536ee97e9887808e84e352022a00393af671ab69d9ba index 99f00a58..f53ab0be 100644 --- a/.resources/2a0d11f91d3434e3998c9168a085bc1d87e698b06e082a8e2f76f9b99305c8a6 +++ b/.resources/5be9bf5bf5b73a329337536ee97e9887808e84e352022a00393af671ab69d9ba @@ -1,6 +1,6 @@ { "custom": { - "color": "#000", + "color": "#f9050d", "modifiedTag": "System/MCM01/VFD/UL14_1_VFD1", "priority": "No Active Alarms" }, diff --git a/.resources/7c5f65b9d2598743af3e3e00c0638417e1eac51c1eabd37d64dc68ddef62ebfd b/.resources/5c2fe95ca2f2fe123ae9fe61b3c41e20c40a449cb320a03505455b272d5ea490 similarity index 80% rename from .resources/7c5f65b9d2598743af3e3e00c0638417e1eac51c1eabd37d64dc68ddef62ebfd rename to .resources/5c2fe95ca2f2fe123ae9fe61b3c41e20c40a449cb320a03505455b272d5ea490 index 74924a30..e71bee87 100644 --- a/.resources/7c5f65b9d2598743af3e3e00c0638417e1eac51c1eabd37d64dc68ddef62ebfd +++ b/.resources/5c2fe95ca2f2fe123ae9fe61b3c41e20c40a449cb320a03505455b272d5ea490 @@ -3,12 +3,54 @@ "PLC": "MCM01", "amperage": 0, "device": "UL15_1_VFD1", + "faultDescription": "", + "faultProbableCause": [ + { + "instancePosition": {}, + "instanceStyle": {}, + "text": "Ambient temperature too high." + }, + { + "instancePosition": {}, + "instanceStyle": {}, + "text": "Fan or ventilation slots are polluted." + }, + { + "instancePosition": {}, + "instanceStyle": {}, + "text": "Fan is defective." + }, + "value", + "value", + "value", + "value" + ], + "faultRemedy": [ + { + "instancePosition": {}, + "instanceStyle": {}, + "text": "Provide for a sufficient cooling of the device." + }, + { + "instancePosition": {}, + "instanceStyle": {}, + "text": "Clean fan and ventilation slots." + }, + { + "instancePosition": {}, + "instanceStyle": {}, + "text": "If required, replace fan." + }, + "value", + "value", + "value" + ], "fpm": 0, "frequency": 0, "lastFaultCode": 0, "maintance_mode": false, "showTags": true, - "state": "Offline", + "state": "FAULTED/DISCONNECTED", "statusCode": 0, "voltage": 0 }, @@ -79,6 +121,77 @@ }, "persistent": true }, + "custom.faultDescription": { + "binding": { + "config": { + "fallbackDelay": 2.5, + "mode": "indirect", + "references": { + "0": "{view.params.tagProps[0]}", + "fc": "{session.custom.fc}" + }, + "tagPath": "[{fc}_SCADA_TAG_PROVIDER]{0}/Fault/Fault_Description" + }, + "transforms": [ + { + "expression": "coalesce({value},\"\")", + "type": "expression" + } + ], + "type": "tag" + }, + "persistent": true + }, + "custom.faultProbableCause": { + "binding": { + "config": { + "fallbackDelay": 2.5, + "mode": "indirect", + "references": { + "0": "{view.params.tagProps[0]}", + "fc": "{session.custom.fc}" + }, + "tagPath": "[{fc}_SCADA_TAG_PROVIDER]{0}/Fault/Fault_Probable_Cause" + }, + "transforms": [ + { + "expression": "coalesce({value},\"\")", + "type": "expression" + }, + { + "code": "\t# Input: a string like \"Ambient temperature too high. || Fan or ventilation slots are polluted. || Fan is defective.\"\n\t# Output: a list of instance dicts for the repeater\n\t\n\titems \u003d []\n\t\n\ttry:\n\t text \u003d str(value).strip()\n\t if text:\n\t # Split by \"||\" and clean up\n\t parts \u003d [p.strip() for p in text.split(\"||\") if p.strip()]\n\t \n\t # Build instance dictionaries\n\t for p in parts:\n\t items.append({\n\t \"instanceStyle\": {},\n\t \"instancePosition\": {},\n\t \"text\": p\n\t })\n\texcept Exception as e:\n\t system.perspective.print(\"FaultItem repeater transform error: \" + str(e))\n\t items \u003d []\n\t\n\treturn items", + "type": "script" + } + ], + "type": "tag" + }, + "persistent": true + }, + "custom.faultRemedy": { + "binding": { + "config": { + "fallbackDelay": 2.5, + "mode": "indirect", + "references": { + "0": "{view.params.tagProps[0]}", + "fc": "{session.custom.fc}" + }, + "tagPath": "[{fc}_SCADA_TAG_PROVIDER]{0}/Fault/Fault_Remedy" + }, + "transforms": [ + { + "expression": "coalesce({value},\"\")", + "type": "expression" + }, + { + "code": "\t# Input: a string like \"Ambient temperature too high. || Fan or ventilation slots are polluted. || Fan is defective.\"\n\t# Output: a list of instance dicts for the repeater\n\t\n\titems \u003d []\n\t\n\ttry:\n\t text \u003d str(value).strip()\n\t if text:\n\t # Split by \"||\" and clean up\n\t parts \u003d [p.strip() for p in text.split(\"||\") if p.strip()]\n\t \n\t # Build instance dictionaries\n\t for p in parts:\n\t items.append({\n\t \"instanceStyle\": {},\n\t \"instancePosition\": {},\n\t \"text\": p\n\t })\n\texcept Exception as e:\n\t system.perspective.print(\"FaultItem repeater transform error: \" + str(e))\n\t items \u003d []\n\t\n\treturn items", + "type": "script" + } + ], + "type": "tag" + }, + "persistent": true + }, "custom.fpm": { "binding": { "config": { @@ -274,6 +387,7 @@ }, "props": { "defaultSize": { + "height": 1080, "width": 600 } }, @@ -935,7 +1049,7 @@ "height": 161, "width": 98, "x": 97.65, - "y": 505.33000000000004 + "y": 455.33 }, "propConfig": { "props.style.backgroundColor": { @@ -975,7 +1089,7 @@ "height": 92, "width": 314, "x": 205.65, - "y": 505.30999999999995 + "y": 455.31 }, "propConfig": { "props.style.backgroundColor": { @@ -1015,7 +1129,7 @@ "height": 64, "width": 98, "x": 205.296, - "y": 602.3 + "y": 552.3 }, "propConfig": { "props.enabled": { @@ -1063,7 +1177,7 @@ "height": 64, "width": 98, "x": 314.65, - "y": 602.29 + "y": 552.29 }, "propConfig": { "props.enabled": { @@ -1111,7 +1225,7 @@ "height": 64, "width": 98, "x": 421.296, - "y": 602.249 + "y": 552.249 }, "propConfig": { "props.enabled": { @@ -1259,6 +1373,231 @@ "y": 381.49 }, "type": "ia.container.flex" + }, + { + "children": [ + { + "meta": { + "name": "Label" + }, + "position": { + "basis": "32px" + }, + "propConfig": { + "props.text": { + "binding": { + "config": { + "expression": "\"LENZE FAULTED : \" + {view.custom.faultDescription}" + }, + "type": "expr" + } + } + }, + "props": { + "style": { + "color": "black", + "paddingLeft": "20px" + } + }, + "type": "ia.display.label" + }, + { + "children": [ + { + "children": [ + { + "meta": { + "name": "Label" + }, + "position": { + "basis": "33px", + "shrink": 0 + }, + "props": { + "style": { + "background": "#d9d9d9", + "color": "#000000" + }, + "text": "Cause", + "textStyle": { + "textAlign": "center" + } + }, + "type": "ia.display.label" + }, + { + "children": [ + { + "meta": { + "name": "FlexRepeater" + }, + "position": { + "basis": "100%" + }, + "propConfig": { + "props.instances": { + "binding": { + "config": { + "path": "view.custom.faultProbableCause" + }, + "type": "property" + } + } + }, + "props": { + "direction": "column", + "path": "autStand/Equipment/VFD-Views/FaultItem", + "style": { + "overflowX": "hidden" + }, + "useDefaultViewWidth": false + }, + "type": "ia.display.flex-repeater" + } + ], + "meta": { + "name": "FlexContainer" + }, + "position": { + "basis": "200px", + "grow": 1 + }, + "props": { + "direction": "column", + "style": { + "borderRight": "solid black 0.5px", + "overflow": "visible" + } + }, + "type": "ia.container.flex" + } + ], + "meta": { + "name": "FlexContainer" + }, + "position": { + "basis": "277px" + }, + "props": { + "direction": "column" + }, + "type": "ia.container.flex" + }, + { + "children": [ + { + "meta": { + "name": "Label" + }, + "position": { + "basis": "33px", + "shrink": 0 + }, + "props": { + "style": { + "background": "#d9d9d9", + "color": "#000000" + }, + "text": "Remedy", + "textStyle": { + "textAlign": "center" + } + }, + "type": "ia.display.label" + }, + { + "children": [ + { + "meta": { + "name": "FlexRepeater" + }, + "position": { + "basis": "100%" + }, + "propConfig": { + "props.instances": { + "binding": { + "config": { + "path": "view.custom.faultRemedy" + }, + "type": "property" + } + } + }, + "props": { + "direction": "column", + "path": "autStand/Equipment/VFD-Views/FaultItem", + "style": { + "overflowX": "hidden" + }, + "useDefaultViewWidth": false + }, + "type": "ia.display.flex-repeater" + } + ], + "meta": { + "name": "FlexContainer" + }, + "position": { + "basis": "200px", + "grow": 1 + }, + "props": { + "direction": "column", + "style": { + "overflow": "visible" + } + }, + "type": "ia.container.flex" + } + ], + "meta": { + "name": "FlexContainer_0" + }, + "position": { + "basis": "277px" + }, + "props": { + "direction": "column", + "style": { + "borderLeft": "solid black 0.5px" + } + }, + "type": "ia.container.flex" + } + ], + "meta": { + "name": "FlexContainer_8" + }, + "position": { + "grow": 1 + }, + "type": "ia.container.flex" + } + ], + "meta": { + "name": "FlexContainer_2" + }, + "position": { + "height": 300, + "width": 508, + "x": 42.33000093823242, + "y": 642.33 + }, + "propConfig": { + "meta.visible": { + "binding": { + "config": { + "expression": "{view.custom.faultDescription} !\u003d \"\"" + }, + "type": "expr" + } + } + }, + "props": { + "direction": "column" + }, + "type": "ia.container.flex" } ], "meta": { diff --git a/.resources/a815b4e202bffa68f84a9a6c2629cc4d57cd7dbc6537f3044dc2f44e214659c8 b/.resources/642c60d8045edb22d61f007d565c68c8f478e6a605506b17207a985c08d3ffea similarity index 99% rename from .resources/a815b4e202bffa68f84a9a6c2629cc4d57cd7dbc6537f3044dc2f44e214659c8 rename to .resources/642c60d8045edb22d61f007d565c68c8f478e6a605506b17207a985c08d3ffea index b1fd0d16..cb91a123 100644 --- a/.resources/a815b4e202bffa68f84a9a6c2629cc4d57cd7dbc6537f3044dc2f44e214659c8 +++ b/.resources/642c60d8045edb22d61f007d565c68c8f478e6a605506b17207a985c08d3ffea @@ -1,8 +1,8 @@ { "custom": { - "color": "#000000", + "color": "#AAAAAA", "deviceName": "S03_CH101_PRX1", - "state": "Offline" + "state": "INACTIVE" }, "params": { "demoColor": -1, diff --git a/.resources/6b0542cefb8458a782a9323acae7d931d03fe7e0dd93f97032f884d966be7d5f b/.resources/713f21e254c52818421adaa31e5fa00e11072d502a3fd1207978638c1629ae5c similarity index 98% rename from .resources/6b0542cefb8458a782a9323acae7d931d03fe7e0dd93f97032f884d966be7d5f rename to .resources/713f21e254c52818421adaa31e5fa00e11072d502a3fd1207978638c1629ae5c index 29293920..e9595ea6 100644 --- a/.resources/6b0542cefb8458a782a9323acae7d931d03fe7e0dd93f97032f884d966be7d5f +++ b/.resources/713f21e254c52818421adaa31e5fa00e11072d502a3fd1207978638c1629ae5c @@ -571,7 +571,7 @@ "dom": { "onClick": { "config": { - "script": "\t#create devices and tags lists for the conveyor\n\tprops \u003d self.view.params.tagProps[0]\n\tautStand.devices.build_device_mapping(props)\n\tdevice_table_dataset \u003d autStand.devices.build_device_table(self)\n\ttags_table_dataset \u003d autStand.devices.getAllTags(self, props)\n\tsystem.perspective.openDock(\u0027Docked-East-Conv\u0027,params\u003d{\u0027tagProps\u0027:self.view.params.tagProps, \"devices\": device_table_dataset, \"tags\":tags_table_dataset})" + "script": "\t#create devices and tags lists for the conveyor\n\tprops \u003d self.view.params.tagProps[0]\n\tautStand.devices.build_device_mapping(props)\n\tdevice_table_dataset \u003d autStand.devices.build_device_table(self)\n\ttags_table_dataset \u003d autStand.devices.getAllTags(self, props, section \u003d \"conveyor\")\n\tsystem.perspective.openDock(\u0027Docked-East-Conv\u0027,params\u003d{\u0027tagProps\u0027:self.view.params.tagProps, \"devices\": device_table_dataset, \"tags\":tags_table_dataset})" }, "scope": "G", "type": "script" diff --git a/.resources/78a0fa4ab6446eee0eff3ab5293daa976179741bf5287d97606ee7deed3a0cef b/.resources/78a0fa4ab6446eee0eff3ab5293daa976179741bf5287d97606ee7deed3a0cef deleted file mode 100644 index 752b9ff3..00000000 Binary files a/.resources/78a0fa4ab6446eee0eff3ab5293daa976179741bf5287d97606ee7deed3a0cef and /dev/null differ diff --git a/.resources/3d55dd301adb523acb7270950a3e234fdafc3aaa7be75a4a3c6ff4ae411128bd b/.resources/7ca002c409fac323994a4f5dcb1e9d5471fb5d8f10cf8293042bdfd216568dae similarity index 98% rename from .resources/3d55dd301adb523acb7270950a3e234fdafc3aaa7be75a4a3c6ff4ae411128bd rename to .resources/7ca002c409fac323994a4f5dcb1e9d5471fb5d8f10cf8293042bdfd216568dae index 5aa45ce7..c79fd876 100644 --- a/.resources/3d55dd301adb523acb7270950a3e234fdafc3aaa7be75a4a3c6ff4ae411128bd +++ b/.resources/7ca002c409fac323994a4f5dcb1e9d5471fb5d8f10cf8293042bdfd216568dae @@ -4,7 +4,7 @@ "$": [ "ds", 192, - 1762166893089 + 1762422327752 ], "$columns": [ { @@ -31,11 +31,11 @@ }, { "data": [ - 20, - 5, + 6, 2, - 36, - 3 + 1, + 32, + 4 ], "name": "Count", "type": "Long" diff --git a/.resources/995510545874f228f60a76b22419634a4dcb4a8e9048b28834839b488cc9ca18 b/.resources/995510545874f228f60a76b22419634a4dcb4a8e9048b28834839b488cc9ca18 new file mode 100644 index 00000000..36211837 Binary files /dev/null and b/.resources/995510545874f228f60a76b22419634a4dcb4a8e9048b28834839b488cc9ca18 differ diff --git a/.resources/78569218c7d783ae73a0710da2292c13d5e5ef952e5ac197ba0b20a59194d733 b/.resources/99f025a6ed3de6d8854c0080c92134cc1ef58d0ff160b1f830722c51e55fc4bf similarity index 98% rename from .resources/78569218c7d783ae73a0710da2292c13d5e5ef952e5ac197ba0b20a59194d733 rename to .resources/99f025a6ed3de6d8854c0080c92134cc1ef58d0ff160b1f830722c51e55fc4bf index c2e2930c..5918c4b7 100644 --- a/.resources/78569218c7d783ae73a0710da2292c13d5e5ef952e5ac197ba0b20a59194d733 +++ b/.resources/99f025a6ed3de6d8854c0080c92134cc1ef58d0ff160b1f830722c51e55fc4bf @@ -3,16 +3,16 @@ "counts": { "Critical": 0, "Diagnostic": 0, - "High": 20, - "Low": 5, - "Medium": 2, - "Total": 27 + "High": 6, + "Low": 2, + "Medium": 1, + "Total": 9 }, "totalAlarms": { "$": [ "ds", 192, - 1762166890980 + 1762422326706 ], "$columns": [ { @@ -39,11 +39,11 @@ }, { "data": [ - 20, - 5, + 6, 2, - 36, - 3 + 1, + 32, + 4 ], "name": "Count", "type": "Long" diff --git a/.resources/a14f4ea8f12b7a91d98b758b1b4c7ae72edc02e2e29d99f5738912319e0b7643 b/.resources/a14f4ea8f12b7a91d98b758b1b4c7ae72edc02e2e29d99f5738912319e0b7643 deleted file mode 100644 index fb0f0175..00000000 Binary files a/.resources/a14f4ea8f12b7a91d98b758b1b4c7ae72edc02e2e29d99f5738912319e0b7643 and /dev/null differ diff --git a/.resources/b8cb970a1edd9ffdd0aa25a2bb8f47eaea008e8e0217847996dee68124e16729 b/.resources/a1a223b976a308318aa96176ce775940e8bb1fb962a6b84df6c51c3132828d2c similarity index 99% rename from .resources/b8cb970a1edd9ffdd0aa25a2bb8f47eaea008e8e0217847996dee68124e16729 rename to .resources/a1a223b976a308318aa96176ce775940e8bb1fb962a6b84df6c51c3132828d2c index 30fe0f98..5db0b6bc 100644 --- a/.resources/b8cb970a1edd9ffdd0aa25a2bb8f47eaea008e8e0217847996dee68124e16729 +++ b/.resources/a1a223b976a308318aa96176ce775940e8bb1fb962a6b84df6c51c3132828d2c @@ -4,7 +4,7 @@ "isHighlited": false, "overlayColor": "#ffffff", "priority": "No Active Alarms", - "state": "Offline" + "state": "BLOCKED" }, "params": { "demoColor": -1, diff --git a/.resources/a802f641406938595e8b7969d8e211e30e67db3d6646adb32da2386213228ddd b/.resources/a802f641406938595e8b7969d8e211e30e67db3d6646adb32da2386213228ddd deleted file mode 100644 index 3fc45bf1..00000000 Binary files a/.resources/a802f641406938595e8b7969d8e211e30e67db3d6646adb32da2386213228ddd and /dev/null differ diff --git a/.resources/b6ac64c10aa035a00000d51da83516c22d2e2ba9d1a54a9221fc46912f0d989d b/.resources/b6ac64c10aa035a00000d51da83516c22d2e2ba9d1a54a9221fc46912f0d989d new file mode 100644 index 00000000..a5024aa1 --- /dev/null +++ b/.resources/b6ac64c10aa035a00000d51da83516c22d2e2ba9d1a54a9221fc46912f0d989d @@ -0,0 +1,111 @@ +{ + "custom": {}, + "params": {}, + "props": { + "defaultSize": { + "height": 920 + } + }, + "root": { + "children": [ + { + "meta": { + "name": "PDFViewer" + }, + "position": { + "height": 1, + "width": 1 + }, + "propConfig": { + "props.page": { + "onChange": { + "enabled": null, + "script": "\tmaxCount \u003d self.props.pageCount\n\tcurrentPage \u003d currentValue.value\n\tif currentPage \u003c 1:\n\t\tself.props.page \u003d maxCount\n\t\n\tif currentPage \u003e maxCount:\n\t\tself.props.page \u003d 1" + } + } + }, + "props": { + "page": 1, + "pageCount": 32, + "source": "\\Description of Operations - Amazon BNA8.pdf", + "style": { + "overflow": "hidden" + } + }, + "type": "ia.display.pdf-viewer" + }, + { + "events": { + "dom": { + "onClick": { + "config": { + "script": "\tself.getSibling(\"PDFViewer\").props.page -\u003d1" + }, + "scope": "G", + "type": "script" + } + } + }, + "meta": { + "name": "Icon_0", + "tooltip": { + "enabled": true, + "text": "Previous Page" + } + }, + "position": { + "height": 0.043, + "width": 0.0587, + "x": 0.4217, + "y": 0.9451 + }, + "props": { + "path": "material/arrow_back", + "style": { + "cursor": "pointer" + } + }, + "type": "ia.display.icon" + }, + { + "events": { + "dom": { + "onClick": { + "config": { + "script": "\tself.getSibling(\"PDFViewer\").props.page +\u003d1" + }, + "scope": "G", + "type": "script" + } + } + }, + "meta": { + "name": "Icon_1", + "tooltip": { + "text": "Next Page" + } + }, + "position": { + "height": 0.043, + "width": 0.0587, + "x": 0.5439, + "y": 0.9451 + }, + "props": { + "path": "material/arrow_forward", + "style": { + "cursor": "painter" + } + }, + "type": "ia.display.icon" + } + ], + "meta": { + "name": "root" + }, + "props": { + "mode": "percent" + }, + "type": "ia.container.coord" + } +} \ No newline at end of file diff --git a/.resources/a024b113e6ba4e92a52b06ae004650153b369ae3b60b995c812d3a92a66ee398 b/.resources/bd82f335870d0625145c337f69351c46d0331d2f5d4a550a93584876c189ec1c similarity index 99% rename from .resources/a024b113e6ba4e92a52b06ae004650153b369ae3b60b995c812d3a92a66ee398 rename to .resources/bd82f335870d0625145c337f69351c46d0331d2f5d4a550a93584876c189ec1c index 8ecb309d..fd27ed20 100644 --- a/.resources/a024b113e6ba4e92a52b06ae004650153b369ae3b60b995c812d3a92a66ee398 +++ b/.resources/bd82f335870d0625145c337f69351c46d0331d2f5d4a550a93584876c189ec1c @@ -3562,7 +3562,7 @@ "height": 0.0231, "width": 0.013, "x": 0.0721, - "y": 0.4037 + "y": 0.3893 }, "props": { "params": { @@ -10069,7 +10069,7 @@ }, { "meta": { - "name": "PS3_12_TPE1" + "name": "PS3_12_TPE2" }, "position": { "height": 0.0231, @@ -10083,7 +10083,7 @@ "props": { "params": { "tagProps": [ - "System/MCM02/PE/TPE/PS3_12_TPE1", + "System/MCM02/PE/TPE/PS3_12_TPE2", "value", "value", "value", @@ -10321,6 +10321,78 @@ } }, "type": "ia.display.view" + }, + { + "meta": { + "name": "PS3_13_ENW2" + }, + "position": { + "height": 0.0231, + "width": 0.0131, + "x": 0.0488, + "y": 0.4583 + }, + "props": { + "params": { + "tagProps": [ + "System/MCM02/ENCODER/ENW/PS3_12_ENW1", + "value", + "value", + "value", + "value", + "value", + "value", + "value", + "value", + "value" + ] + }, + "path": "autStand/Equipment/Encoder", + "style": { + "borderRadius": "50%", + "classes": "hover", + "overflow": "visible" + } + }, + "type": "ia.display.view" + }, + { + "meta": { + "name": "PS3_12_TPE1" + }, + "position": { + "height": 0.0231, + "rotate": { + "angle": "90deg" + }, + "width": 0.0531, + "x": 0.0543, + "y": 0.4473 + }, + "props": { + "params": { + "tagProps": [ + "System/MCM02/PE/TPE/PS3_12_TPE1", + "value", + "value", + "value", + "value", + "value", + "value", + "value", + "value", + "value" + ] + }, + "path": "autStand/Equipment/Photoeye_Chute", + "style": { + "classes": "hover-90", + "overflow": "visible" + }, + "useDefaultViewHeight": true, + "useDefaultViewWidth": true + }, + "type": "ia.display.view" } ], "meta": { diff --git a/.resources/03ef3fa26c66a7511058ad3be4e4beef0417c79875fe13f8142b8f297e512229 b/.resources/d50c6f38e27051c19229dac4e5715d4761dfd6352b2ad8dca21694e62ddf878c similarity index 99% rename from .resources/03ef3fa26c66a7511058ad3be4e4beef0417c79875fe13f8142b8f297e512229 rename to .resources/d50c6f38e27051c19229dac4e5715d4761dfd6352b2ad8dca21694e62ddf878c index 01b492f2..4eea33d0 100644 --- a/.resources/03ef3fa26c66a7511058ad3be4e4beef0417c79875fe13f8142b8f297e512229 +++ b/.resources/d50c6f38e27051c19229dac4e5715d4761dfd6352b2ad8dca21694e62ddf878c @@ -4,7 +4,7 @@ "divertingLeft": false, "divertingRight": false, "priority": "No Active Alarms", - "state": "Offline" + "state": "Closed" }, "params": { "demoColor": 0, diff --git a/.resources/75e60d8dd5f1877648c3d33191e96120b464e772219c233f1cf267e0d0849652 b/.resources/e69f326920e76878cc5ba035aec5564a9fcadebb49b8bd6d8009eb5c7c5fabf0 similarity index 98% rename from .resources/75e60d8dd5f1877648c3d33191e96120b464e772219c233f1cf267e0d0849652 rename to .resources/e69f326920e76878cc5ba035aec5564a9fcadebb49b8bd6d8009eb5c7c5fabf0 index f5e9dc9c..11e599ed 100644 --- a/.resources/75e60d8dd5f1877648c3d33191e96120b464e772219c233f1cf267e0d0849652 +++ b/.resources/e69f326920e76878cc5ba035aec5564a9fcadebb49b8bd6d8009eb5c7c5fabf0 @@ -574,7 +574,7 @@ "dom": { "onClick": { "config": { - "script": "\t#create devices and tags lists for the conveyor\n\tprops \u003d self.view.params.tagProps[0]\n\tautStand.devices.build_device_mapping(props)\n\tdevice_table_dataset \u003d autStand.devices.build_device_table(self)\n\ttags_table_dataset \u003d autStand.devices.getAllTags(self, props)\n\tsystem.perspective.openDock(\u0027Docked-East-Conv\u0027,params\u003d{\u0027tagProps\u0027:self.view.params.tagProps, \"devices\": device_table_dataset, \"tags\":tags_table_dataset})" + "script": "\t#create devices and tags lists for the conveyor\n\tprops \u003d self.view.params.tagProps[0]\n\tautStand.devices.build_device_mapping(props)\n\tdevice_table_dataset \u003d autStand.devices.build_device_table(self)\n\ttags_table_dataset \u003d autStand.devices.getAllTags(self, props, section \u003d \"conveyor\")\n\tsystem.perspective.openDock(\u0027Docked-East-Conv\u0027,params\u003d{\u0027tagProps\u0027:self.view.params.tagProps, \"devices\": device_table_dataset, \"tags\":tags_table_dataset})" }, "scope": "G", "type": "script" diff --git a/.resources/fe9bae2359742309a03943ffbfa25dc3665edd67ffa11b17713ae109a1f0cb08 b/.resources/fe9bae2359742309a03943ffbfa25dc3665edd67ffa11b17713ae109a1f0cb08 new file mode 100644 index 00000000..f2ef9571 --- /dev/null +++ b/.resources/fe9bae2359742309a03943ffbfa25dc3665edd67ffa11b17713ae109a1f0cb08 @@ -0,0 +1,542 @@ +import os, json, sys + +# ====================================================== +# Helper Function: State Resolver +# ====================================================== +def get_device_state(value, tagPath): + up = tagPath.upper() + + # === Base state dictionary === + state_mappings = { + 0: "Closed", + 1: "Actuated", + 2: "Communication Faulted", + 3: "Conveyor Running In Maintenance Mode", + 4: "Disabled", + 5: "Disconnected", + 6: "Stopped", + 7: "Enabled Not Running", + 8: "Encoder Fault", + 9: "Energy Management", + 10: "ESTOP Was Actuated", + 11: "EStopped", + 12: "EStopped Locally", + 13: "Extended Faulted", + 14: "Full", + 15: "Gaylord Start Pressed", + 16: "Jam Fault", + 17: "Jammed", + 18: "Loading Allowed", + 19: "Loading Not Allowed", + 20: "Low Air Pressure Fault Was Present", + 21: "Maintenance Mode", + 22: "Conveyor Stopped In Maintenance Mode", + 23: "Motor Faulted", + 24: "Motor Was Faulted", + 25: "Normal", + 26: "Off Inactive", + 27: "Open", + 28: "PLC Ready To Run", + 29: "Package Release Pressed", + 30: "Power Branch Was Faulted", + 31: "Pressed", + 32: "Ready To Receive", + 33: "Running", + 34: "Started", + 35: "Stopped", + 36: "System Started", + 37: "Unknown", + 38: "VFD Fault", + 39: "Conveyor Running In Power Saving Mode", + 40: "Conveyor Jogging In Maintenance Mode", + 41: "VFD Reset Required", + 42: "Jam Reset Push Button Pressed", + 43: "Start Push Button Pressed", + 44: "Stop Push Button Pressed", + 45: "No Container", + 46: "Ready To Be Enabled", + 47: "Half Full", + 48: "Enabled", + 49: "Tipper Faulted", + 50: "OK", + 51: "Disconnected", + 52: "Faulted", + 53: "Faulted/Disconnect", + 54: "Diverting" + } + + # === TPE (Tracking Photoeye) === + if "/TPE/" in up: + if value == 0: + return "Blocked" + elif value == 27: + return "Clear" + elif value == 17: + return "Jammed" + else: + return state_mappings.get(value, "Unknown") + + # === Single Photoeyes (PE1, PE2) === + if up.endswith(("PE1", "PE2")): + if not value: + return "Clear" + else: + return "Blocked" + + # === Prox Sensors (PRX1, PRX2) === + if up.endswith(("PRX1", "PRX2")): + if not value: + return "Inactive" + else: + return "Actuated" + + # === Beacons (BCN) === + if "/BEACON" in up: + if value == 0: + return "Off" + elif value == 1: + return "Cleared / Reset Required" + else: + return "Active" + + # === Default === + return state_mappings.get(value, "Unknown") + + +# ====================================================== +# Helper Function: Read One Device (multi or single state) +# ====================================================== +def read_device_status(tagPath, provider, dev_name): + """ + Reads the appropriate state tag(s) for a given device and returns + a list of {Device, Status} dictionaries. + Handles multi-state (SS), VFD, PRX, PE, EN, etc. + """ + rows = [] + try: + up = tagPath.upper() + + # === Case 0: SS (Start/Stop Station) === + if up.endswith("SS") or "/SS/" in up: + for sub in ("Start", "Stop"): + sub_path = provider + tagPath + "/" + sub + "/State" + try: + result = system.tag.readBlocking([sub_path])[0] + if result.quality.isGood(): + status_value = get_device_state(result.value, tagPath) + else: + status_value = "Unknown" + except: + status_value = "Unknown" + + rows.append({ + "Device": "{} ({})".format(dev_name, sub), + "Status": status_value + }) + return rows # handled fully + + # === Case 1: VFD / Conveyor === + if "/VFD/" in up: + path = provider + tagPath + "/Drive/Lenze" + + # === Case 2: Chute sensors (PE / PRX) === + elif up.endswith(("PE1", "PE2", "PRX1", "PRX2")) and "/TPE/" not in up: + path = provider + tagPath + + # === Case 3: Chute EN === + elif up.endswith("EN") and "/CHUTE/" in up: + path = provider + tagPath + "_State" + + # === Case 4: Default === + else: + path = provider + tagPath + "/State" + + try: + result = system.tag.readBlocking([path])[0] + if result.quality.isGood(): + status_value = get_device_state(result.value, tagPath) + else: + status_value = "Offline" + except: + status_value = "Offline" + + rows.append({ + "Device": dev_name, + "Status": status_value + }) + + except Exception as e: + system.perspective.print("Error reading device status for %s: %s" % (dev_name, e)) + + return rows + + +# ====================================================== +# Helper Function: Single Device Reader (for Docked Device View) +# ====================================================== +def get_single_device_status(self, tagPath): + """ + Reads a single device tag (used for docked device views). + Returns a single readable status string (e.g. "Running", "Blocked", etc.) + """ + try: + up = tagPath.upper() + provider = "[" + self.session.custom.fc + "_SCADA_TAG_PROVIDER]" + + if up.endswith("SS") or "/SS/" in up: + states = [] + for sub in ("Start", "Stop"): + sub_path = provider + tagPath + "/" + sub + "/State" + try: + result = system.tag.readBlocking([sub_path])[0] + if result.quality.isGood(): + states.append("{}: {}".format(sub, get_device_state(result.value, tagPath))) + else: + states.append("{}: Unknown".format(sub)) + except: + states.append("{}: Unknown".format(sub)) + return " | ".join(states) + + # === VFD === + if "/VFD/" in up: + path = provider + tagPath + "/Drive/Lenze" + # === Sensors === + elif up.endswith(("PE1", "PE2", "PRX1", "PRX2")) and "/TPE/" not in up: + path = provider + tagPath + # === EN === + elif up.endswith("EN") and "/CHUTE/" in up: + path = provider + tagPath + "_State" + else: + path = provider + tagPath + "/State" + + result = system.tag.readBlocking([path])[0] + if result.quality.isGood(): + return get_device_state(result.value, tagPath) + else: + return "Unknown" + + except Exception as e: + system.perspective.print("Error reading single device status for %s: %s" % (tagPath, e)) + return "Unknown" + + +# ====================================================== +# Device Mapping Builder +# ====================================================== +global_device_mapping = {} + +def build_device_mapping(full_tag_path): + """ + Builds global_device_mapping for devices under the same PLC and parent device. + Adds support for: + - Chute FIOM devices (e.g. S03_CH109_FIOM_1 when clicking S03_CH109) + - Shared JR and PE devices used by multiple chutes (e.g. S03_1_JR1, S03_1_LRPE1) + """ + system.perspective.print(full_tag_path) + global global_device_mapping + global_device_mapping.clear() + + try: + path_parts = full_tag_path.split("/") + plc_name = path_parts[1] if len(path_parts) > 1 else path_parts[0] + clicked_name = path_parts[-1] if len(path_parts) > 0 else "" + + # --- Clean clicked name --- + if "_VFD" in clicked_name: + clicked_name = clicked_name.split("_VFD")[0] + + project_name = system.util.getProjectName() + base_path = ( + os.getcwd().replace("\\", "/") + + "/data/projects/" + + project_name + + "/com.inductiveautomation.perspective/Views/autStand/Detailed_Views/MCM-Views" + ) + + if not os.path.exists(base_path): + system.perspective.print("Path not found: " + base_path) + return {} + + # --- Detect if this is a Chute --- + is_chute = "/CHUTE/" in full_tag_path.upper() + + for view_folder in os.listdir(base_path): + json_file = os.path.join(base_path, view_folder, "view.json") + if not os.path.isfile(json_file): + continue + + try: + with open(json_file, "r") as fh: + view_json = json.load(fh) + except Exception: + continue + + root_children = (view_json.get("root") or {}).get("children") or [] + if not root_children: + continue + + container = root_children[0] + children = container.get("children") or [] + + for child in children: + props = child.get("props") or {} + params = props.get("params") or {} + tag_props = params.get("tagProps") + + if isinstance(tag_props, list) and len(tag_props) > 0: + tag_prop = str(tag_props[0]) + parts = tag_prop.split("/") + + if len(parts) > 1 and parts[1] == plc_name: + dev_name = parts[-1] + if len(parts) > 3 and parts[-2] == clicked_name: + dev_name = clicked_name + "_" + parts[-1] + else: + dev_name = parts[-1] + + prefix = clicked_name + "_" + + # === 🟢 NEW: Chute FIOM match === + if is_chute and dev_name.startswith(clicked_name + "_"): + global_device_mapping[dev_name] = { + "tagPath": tag_prop, + "zone": view_folder + } + continue + + # === Default inclusion === + if dev_name.startswith(prefix) or (len(parts) > 3 and parts[-2] == clicked_name): + global_device_mapping[dev_name] = { + "tagPath": tag_prop, + "zone": view_folder + } + + # === Special Case: JR Buttons === + elif "/JR/" in tag_prop.upper(): + try: + jr_parts = tag_prop.split("/JR/") + if len(jr_parts) > 1: + sub_path = jr_parts[1] + if sub_path.startswith(clicked_name + "_JR"): + dev_name = sub_path.split("/")[0] + global_device_mapping[dev_name] = { + "tagPath": tag_prop, + "zone": view_folder + } + except: + pass + + shared_jr_pe_map = { + "S03_CH101": ["S03_1_JR1", "S03_1_LRPE1"], + "S03_CH103": ["S03_1_JR1", "S03_1_LRPE1"], + "S03_CH105": ["S03_1_JR1", "S03_1_LRPE1"], + "S03_CH107": ["S03_1_JR3", "S03_1_LRPE3"], + "S03_CH108": ["S03_1_JR4", "S03_1_LRPE4"], + "S03_CH109": ["S03_1_JR3", "S03_1_LRPE3"], + "S03_CH110": ["S03_1_JR4", "S03_1_LRPE4"], + "S03_CH111": ["S03_1_JR3", "S03_1_LRPE3"], + "S03_CH112": ["S03_1_JR2", "S03_1_LRPE2"], + "S03_CH113": ["S03_1_JR5", "S03_1_LRPE5"], + "S03_CH114": ["S03_1_JR6", "S03_1_LRPE6"], + "S03_CH115": ["S03_1_JR5", "S03_1_LRPE5"], + "S03_CH116": ["S03_1_JR6", "S03_1_LRPE6"], + "S03_CH117": ["S03_1_JR5", "S03_1_LRPE5"], + "S03_CH118": ["S03_1_JR6", "S03_1_LRPE6"], + "S03_CH119": ["S03_1_JR7", "S03_1_LRPE7"], + "S03_CH120": ["S03_1_JR8", "S03_1_LRPE8"], + "S03_CH121": ["S03_1_JR7", "S03_1_LRPE7"], + "S03_CH122": ["S03_1_JR8", "S03_1_LRPE8"], + "S03_CH123": ["S03_1_JR7", "S03_1_LRPE7"], + "S03_CH124": ["S03_1_JR8", "S03_1_LRPE8"], + } + shared_fiom_map = { + "NCS1_1": ["S03_1_FIOM_5", "S03_1_FIOM_9", "S03_1_FIOM_1", "S03_1_FIOM_2","S03_1_FIOM_3","S03_1_FIOM_4", "S03_1_FIOM_6","S03_1_FIOM_7", "S03_1_FIOM_8"], + } + + if clicked_name in shared_jr_pe_map: + extra_devices = shared_jr_pe_map[clicked_name] + for dev in extra_devices: + try: + # Base tag (for PE) + base_tag = "System/MCM02/Station/Chute_JR/" + dev + # JR subtag (for JR button) + jr_tag = base_tag + "/JR" if dev.endswith("JR1") else base_tag + + for tag_candidate in [base_tag, jr_tag]: + global_device_mapping[dev] = { + "tagPath": tag_candidate, + "zone": "Chute_JR" + } + except Exception as ex: + system.perspective.print("Error adding JR/PE for {}: {}".format(clicked_name, ex)) + + if clicked_name in shared_fiom_map: + for dev in shared_fiom_map[clicked_name]: + tag_path = "System/{}/IO_Block/FIO/{}".format(plc_name, dev) + global_device_mapping[dev] = { + "tagPath": tag_path, + "zone": "FIO" + } + + return global_device_mapping + + except Exception as e: + whid = "unknown" + try: + whid = system.tag.readBlocking("Configuration/FC")[0].value + except: + pass + logger = system.util.getLogger("%s-build_device_mapping" % whid) + exc_type, exc_obj, tb = sys.exc_info() + logger.error("Error at line %s: %s" % (tb.tb_lineno, exc_obj)) + return {} + + + + +# ====================================================== +# Device Table Builder +# ====================================================== +def build_device_table(self): + rows = [] + try: + for dev_name, info in global_device_mapping.items(): + tagPath = info.get("tagPath", "") + if not tagPath: + continue + + provider = "[" + self.session.custom.fc + "_SCADA_TAG_PROVIDER]" + rows.extend(read_device_status(tagPath, provider, dev_name)) + + return rows + + except Exception as e: + system.perspective.print("Error building device table: %s" % e) + return [] + +# ====================================================== +# Get All Tags for Clicked Device +# ====================================================== +def getAllTags(self, tagPath, section="all"): + """ + Reads all tags under a UDT instance (recursively) + and returns a list of dictionaries: + [ + {"Name": "State", "OPC Path": "System/MCM01/...", "Value": "Running"}, + ... + ] + """ + rows = [] + + try: + providerPath = "[" + self.session.custom.fc + "_SCADA_TAG_PROVIDER]" + driveFolderName = "Drive" + + # === Utility: read a single atomic tag === + def readSingleTag(path, prefix=""): + try: + result = system.tag.readBlocking([providerPath + path])[0] + value = str(result.value) if result.quality.isGood() else "Unknown" + except: + value = "Unknown" + + displayName = prefix + path.split("/")[-1] if prefix else path.split("/")[-1] + rows.append({ + "Name": displayName, + "OPC Path": path, + "Value": value + }) + + # === Utility: recursive browse === + def browseRecursive(basePath, prefix=""): + children = system.tag.browse(providerPath + basePath).getResults() + for child in children: + tagType = str(child.get("tagType", "")) + name = str(child.get("name", "")) + fullPath = str(child.get("fullPath", "")) + + if fullPath.startswith("[") and "]" in fullPath: + fullPath = fullPath.split("]", 1)[1] + + # --- Conveyor filter (skip Drive folder) --- + if section == "conveyor" and name == driveFolderName: + continue + + if tagType == "Folder": + # --- Skip JR subfolder if current device is LRPE --- + if name.upper() == "JR" and "_JR" in basePath.upper(): + continue + newPrefix = prefix + name + "/" if prefix else name + "/" + browseRecursive(basePath + "/" + name, newPrefix) + elif tagType == "AtomicTag": + readSingleTag(fullPath, prefix) + + # === MAIN ENTRY POINT === + + # --- Case 1: VFD --- + if section == "vfd": + drivePath = tagPath + "/" + driveFolderName + browseRecursive(drivePath) + + # --- Case 2: Flat EN_ tags (Chutes) --- + elif tagPath.upper().endswith("/EN"): + parentPath = "/".join(tagPath.split("/")[:-1]) + children = system.tag.browse(providerPath + parentPath).getResults() + for child in children: + tagType = str(child.get("tagType", "")) + name = str(child.get("name", "")) + if tagType == "AtomicTag" and name.upper().startswith("EN_"): + fullPath = str(child.get("fullPath", "")) + if fullPath.startswith("[") and "]" in fullPath: + fullPath = fullPath.split("]", 1)[1] + readSingleTag(fullPath) + + # --- Case 3: Single Sensors (PE/PRX) --- + elif tagPath.upper().endswith(("PE1", "PE2", "PRX1", "PRX2")) and "/TPE/" not in tagPath.upper(): + readSingleTag(tagPath) + + # --- Case 4: Default / Fallback --- + else: + browseResult = system.tag.browse(providerPath + tagPath).getResults() + + if not browseResult: + # Possibly a struct-style UDT (like some TPEs) + system.perspective.print("Empty browse for {}, checking struct value...".format(tagPath)) + try: + result = system.tag.readBlocking([providerPath + tagPath])[0] + value = result.value + + # === Expand STRUCT === + if isinstance(value, dict): + system.perspective.print("Detected STRUCT value, expanding {}".format(tagPath)) + + def flattenStruct(struct, base=""): + for k, v in struct.items(): + newName = base + "/" + k if base else k + if isinstance(v, dict): + flattenStruct(v, newName) + else: + rows.append({ + "Name": newName, + "OPC Path": tagPath + "/" + newName, + "Value": str(v) + }) + + flattenStruct(value) + + else: + # Not a struct, read normally + readSingleTag(tagPath) + + except Exception as ex: + system.perspective.print("Fallback read failed for {}: {}".format(tagPath, ex)) + + else: + # Normal browse case + browseRecursive(tagPath) + + return rows + + except Exception as e: + system.perspective.print("Error in getAllTags: {}".format(e)) + return [] diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM-Views/MCM01/resource.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM-Views/MCM01/resource.json index 40fd86d3..94332764 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM-Views/MCM01/resource.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM-Views/MCM01/resource.json @@ -10,8 +10,8 @@ "attributes": { "lastModification": { "actor": "admin", - "timestamp": "2025-11-04T15:20:44Z" + "timestamp": "2025-11-05T14:27:38Z" }, - "lastModificationSignature": "7aefd1d334d282d738eaf97f9245f751ec78e796123dc60f1c7cf6f0df39e039" + "lastModificationSignature": "de4d878ca08fcb3581ac8deb45ba0df2b6cfa9e6e54a588bef5c7089f40a3524" } } \ No newline at end of file diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM-Views/MCM02/resource.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM-Views/MCM02/resource.json index 27e0624f..c5c6d441 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM-Views/MCM02/resource.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM-Views/MCM02/resource.json @@ -10,8 +10,8 @@ "attributes": { "lastModification": { "actor": "admin", - "timestamp": "2025-11-05T10:10:15Z" + "timestamp": "2025-11-06T09:07:51Z" }, - "lastModificationSignature": "93ca78bdef1d5678a8d5ec0bdb7adb2d459d940aa32e842ff0e0bedb902aad35" + "lastModificationSignature": "69538fe7e0bc707101c3e0349c42569d245b26f2d01e548dc6d6409daded6bad" } } \ No newline at end of file diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM-Views/MCM02/thumbnail.png b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM-Views/MCM02/thumbnail.png index 752b9ff3..e5d311d4 100644 Binary files a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM-Views/MCM02/thumbnail.png and b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM-Views/MCM02/thumbnail.png differ diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM-Views/MCM02/view.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM-Views/MCM02/view.json index 8ecb309d..fd27ed20 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM-Views/MCM02/view.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Detailed_Views/MCM-Views/MCM02/view.json @@ -3562,7 +3562,7 @@ "height": 0.0231, "width": 0.013, "x": 0.0721, - "y": 0.4037 + "y": 0.3893 }, "props": { "params": { @@ -10069,7 +10069,7 @@ }, { "meta": { - "name": "PS3_12_TPE1" + "name": "PS3_12_TPE2" }, "position": { "height": 0.0231, @@ -10083,7 +10083,7 @@ "props": { "params": { "tagProps": [ - "System/MCM02/PE/TPE/PS3_12_TPE1", + "System/MCM02/PE/TPE/PS3_12_TPE2", "value", "value", "value", @@ -10321,6 +10321,78 @@ } }, "type": "ia.display.view" + }, + { + "meta": { + "name": "PS3_13_ENW2" + }, + "position": { + "height": 0.0231, + "width": 0.0131, + "x": 0.0488, + "y": 0.4583 + }, + "props": { + "params": { + "tagProps": [ + "System/MCM02/ENCODER/ENW/PS3_12_ENW1", + "value", + "value", + "value", + "value", + "value", + "value", + "value", + "value", + "value" + ] + }, + "path": "autStand/Equipment/Encoder", + "style": { + "borderRadius": "50%", + "classes": "hover", + "overflow": "visible" + } + }, + "type": "ia.display.view" + }, + { + "meta": { + "name": "PS3_12_TPE1" + }, + "position": { + "height": 0.0231, + "rotate": { + "angle": "90deg" + }, + "width": 0.0531, + "x": 0.0543, + "y": 0.4473 + }, + "props": { + "params": { + "tagProps": [ + "System/MCM02/PE/TPE/PS3_12_TPE1", + "value", + "value", + "value", + "value", + "value", + "value", + "value", + "value", + "value" + ] + }, + "path": "autStand/Equipment/Photoeye_Chute", + "style": { + "classes": "hover-90", + "overflow": "visible" + }, + "useDefaultViewHeight": true, + "useDefaultViewWidth": true + }, + "type": "ia.display.view" } ], "meta": { diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Docked_Views/Controller-Equipment/Information-Docked-East-Conv/resource.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Docked_Views/Controller-Equipment/Information-Docked-East-Conv/resource.json index 43e87f74..6f665906 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Docked_Views/Controller-Equipment/Information-Docked-East-Conv/resource.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Docked_Views/Controller-Equipment/Information-Docked-East-Conv/resource.json @@ -10,8 +10,8 @@ "attributes": { "lastModification": { "actor": "admin", - "timestamp": "2025-11-05T10:19:56Z" + "timestamp": "2025-11-06T07:10:44Z" }, - "lastModificationSignature": "43d1be0664c71a5e4d3d4aabd47c7de302c43a5c16b73253ee224b331c75f8b0" + "lastModificationSignature": "3ec9d44b3da00172f7274ea7375a30869247ebe90d8164e8382a4589a7b8c543" } } \ No newline at end of file diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Docked_Views/Controller-Equipment/Information-Docked-East-Conv/view.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Docked_Views/Controller-Equipment/Information-Docked-East-Conv/view.json index 2f431a15..2dbbe3da 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Docked_Views/Controller-Equipment/Information-Docked-East-Conv/view.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Docked_Views/Controller-Equipment/Information-Docked-East-Conv/view.json @@ -3,7 +3,7 @@ "PLC": "MCM01", "color": "#C2C2C2", "showTags": true, - "state": "Offline" + "state": "Closed" }, "params": { "devices": [], diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Docked_Views/Controller-Equipment/Information-Docked-East-Device/resource.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Docked_Views/Controller-Equipment/Information-Docked-East-Device/resource.json index 82d8dd99..504d57d2 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Docked_Views/Controller-Equipment/Information-Docked-East-Device/resource.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Docked_Views/Controller-Equipment/Information-Docked-East-Device/resource.json @@ -10,8 +10,8 @@ "attributes": { "lastModification": { "actor": "admin", - "timestamp": "2025-11-05T10:10:15Z" + "timestamp": "2025-11-06T06:30:46Z" }, - "lastModificationSignature": "b2d0d45ff1c80965505c780bd723721a4160fa8eb9dd6d8e8b303967a53cb7a3" + "lastModificationSignature": "d10ceafdc901b383a0a4411bd8d28abd097f520027017a0482d5ec2e2ac1ed94" } } \ No newline at end of file diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Docked_Views/Controller-Equipment/Information-Docked-East-Device/view.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Docked_Views/Controller-Equipment/Information-Docked-East-Device/view.json index 8ec9703f..25165cbe 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Docked_Views/Controller-Equipment/Information-Docked-East-Device/view.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Docked_Views/Controller-Equipment/Information-Docked-East-Device/view.json @@ -71,232 +71,6 @@ "persistent": true }, "custom.state": { - "binding": { - "config": { - "fallbackDelay": 2.5, - "mode": "indirect", - "references": { - "0": "{view.params.tagProps[0]}", - "fc": "{session.custom.fc}" - }, - "tagPath": "[{fc}_SCADA_TAG_PROVIDER]{0}/State" - }, - "transforms": [ - { - "expression": "coalesce({value},-1)", - "type": "expression" - }, - { - "fallback": "Offline", - "inputType": "scalar", - "mappings": [ - { - "input": 0, - "output": "Closed" - }, - { - "input": 1, - "output": "Actuated" - }, - { - "input": 2, - "output": "Communication Faulted" - }, - { - "input": 3, - "output": "Conveyor Running In Maintenance Mode" - }, - { - "input": 4, - "output": "Disabled" - }, - { - "input": 5, - "output": "Disconnected" - }, - { - "input": 6, - "output": "Stopped" - }, - { - "input": 7, - "output": "Enabled Not Running" - }, - { - "input": 8, - "output": "Encoder Fault" - }, - { - "input": 9, - "output": "Energy Management" - }, - { - "input": 10, - "output": "ESTOP Was Actuated" - }, - { - "input": 11, - "output": "EStopped" - }, - { - "input": 12, - "output": "EStopped Locally" - }, - { - "input": 13, - "output": "Extended Faulted" - }, - { - "input": 14, - "output": "Full" - }, - { - "input": 15, - "output": "Gaylord Start Pressed" - }, - { - "input": 16, - "output": "Jam Fault" - }, - { - "input": 17, - "output": "Jammed" - }, - { - "input": 18, - "output": "Loading Allowed" - }, - { - "input": 19, - "output": "Loading Not Allowed" - }, - { - "input": 20, - "output": "Low Air Pressure Fault Was Present" - }, - { - "input": 21, - "output": "Maintenance Mode" - }, - { - "input": 22, - "output": "Conveyor Stopped In Maintenance Mode" - }, - { - "input": 23, - "output": "Motor Faulted" - }, - { - "input": 24, - "output": "Motor Was Faulted" - }, - { - "input": 25, - "output": "Normal" - }, - { - "input": 26, - "output": "Off Inactive" - }, - { - "input": 27, - "output": "Open" - }, - { - "input": 28, - "output": "PLC Ready To Run" - }, - { - "input": 29, - "output": "Package Release Pressed" - }, - { - "input": 30, - "output": "Power Branch Was Faulted" - }, - { - "input": 31, - "output": "Pressed" - }, - { - "input": 32, - "output": "Ready To Receive" - }, - { - "input": 33, - "output": "Running" - }, - { - "input": 34, - "output": "Started" - }, - { - "input": 35, - "output": "Stopped" - }, - { - "input": 36, - "output": "System Started" - }, - { - "input": 37, - "output": "Unknown" - }, - { - "input": 38, - "output": "VFD Fault" - }, - { - "input": 39, - "output": "Conveyor Running In Power Saving Mode" - }, - { - "input": 40, - "output": "Conveyor Jogging In Maintenance Mode" - }, - { - "input": 41, - "output": "VFD Reset Required" - }, - { - "input": 42, - "output": "Jam Reset Push Button Pressed" - }, - { - "input": 43, - "output": "Start Push Button Pressed" - }, - { - "input": 44, - "output": "Stop Push Button Pressed" - }, - { - "input": 45, - "output": "No Container" - }, - { - "input": 46, - "output": "Ready To Be Enabled" - }, - { - "input": 47, - "output": "Half Full" - }, - { - "input": 48, - "output": "Enabled" - }, - { - "input": 49, - "output": "Tipper Faulted" - } - ], - "outputType": "scalar", - "type": "map" - } - ], - "type": "tag" - }, "persistent": true }, "custom.view": { @@ -307,6 +81,10 @@ "persistent": true }, "params.tagProps": { + "onChange": { + "enabled": null, + "script": "\ttagPath \u003d currentValue.value[0].value #I know this looks ugly\t\t\t\n\tstatus \u003d autStand.devices.get_single_device_status(self, tagPath)\n\tself.view.custom.state \u003d status\n\n" + }, "paramDirection": "input", "persistent": true }, diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Docked_Views/Controller-Equipment/Information-Docked-East-VFD/resource.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Docked_Views/Controller-Equipment/Information-Docked-East-VFD/resource.json index db4ccdd7..6c63f067 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Docked_Views/Controller-Equipment/Information-Docked-East-VFD/resource.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Docked_Views/Controller-Equipment/Information-Docked-East-VFD/resource.json @@ -10,8 +10,8 @@ "attributes": { "lastModification": { "actor": "admin", - "timestamp": "2025-11-05T10:06:34Z" + "timestamp": "2025-11-06T10:48:24Z" }, - "lastModificationSignature": "4ecba60a0ac1422450b0014b8931ec222fa721d33dace06608f36c9d4237d607" + "lastModificationSignature": "15f70498ff0d20fac7dd1f3668d7659faf171f84d8964bd1bb19f3a9e6cc0bb3" } } \ No newline at end of file diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Docked_Views/Controller-Equipment/Information-Docked-East-VFD/thumbnail.png b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Docked_Views/Controller-Equipment/Information-Docked-East-VFD/thumbnail.png index 3fc45bf1..36211837 100644 Binary files a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Docked_Views/Controller-Equipment/Information-Docked-East-VFD/thumbnail.png and b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Docked_Views/Controller-Equipment/Information-Docked-East-VFD/thumbnail.png differ diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Docked_Views/Controller-Equipment/Information-Docked-East-VFD/view.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Docked_Views/Controller-Equipment/Information-Docked-East-VFD/view.json index 74924a30..e71bee87 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Docked_Views/Controller-Equipment/Information-Docked-East-VFD/view.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Docked_Views/Controller-Equipment/Information-Docked-East-VFD/view.json @@ -3,12 +3,54 @@ "PLC": "MCM01", "amperage": 0, "device": "UL15_1_VFD1", + "faultDescription": "", + "faultProbableCause": [ + { + "instancePosition": {}, + "instanceStyle": {}, + "text": "Ambient temperature too high." + }, + { + "instancePosition": {}, + "instanceStyle": {}, + "text": "Fan or ventilation slots are polluted." + }, + { + "instancePosition": {}, + "instanceStyle": {}, + "text": "Fan is defective." + }, + "value", + "value", + "value", + "value" + ], + "faultRemedy": [ + { + "instancePosition": {}, + "instanceStyle": {}, + "text": "Provide for a sufficient cooling of the device." + }, + { + "instancePosition": {}, + "instanceStyle": {}, + "text": "Clean fan and ventilation slots." + }, + { + "instancePosition": {}, + "instanceStyle": {}, + "text": "If required, replace fan." + }, + "value", + "value", + "value" + ], "fpm": 0, "frequency": 0, "lastFaultCode": 0, "maintance_mode": false, "showTags": true, - "state": "Offline", + "state": "FAULTED/DISCONNECTED", "statusCode": 0, "voltage": 0 }, @@ -79,6 +121,77 @@ }, "persistent": true }, + "custom.faultDescription": { + "binding": { + "config": { + "fallbackDelay": 2.5, + "mode": "indirect", + "references": { + "0": "{view.params.tagProps[0]}", + "fc": "{session.custom.fc}" + }, + "tagPath": "[{fc}_SCADA_TAG_PROVIDER]{0}/Fault/Fault_Description" + }, + "transforms": [ + { + "expression": "coalesce({value},\"\")", + "type": "expression" + } + ], + "type": "tag" + }, + "persistent": true + }, + "custom.faultProbableCause": { + "binding": { + "config": { + "fallbackDelay": 2.5, + "mode": "indirect", + "references": { + "0": "{view.params.tagProps[0]}", + "fc": "{session.custom.fc}" + }, + "tagPath": "[{fc}_SCADA_TAG_PROVIDER]{0}/Fault/Fault_Probable_Cause" + }, + "transforms": [ + { + "expression": "coalesce({value},\"\")", + "type": "expression" + }, + { + "code": "\t# Input: a string like \"Ambient temperature too high. || Fan or ventilation slots are polluted. || Fan is defective.\"\n\t# Output: a list of instance dicts for the repeater\n\t\n\titems \u003d []\n\t\n\ttry:\n\t text \u003d str(value).strip()\n\t if text:\n\t # Split by \"||\" and clean up\n\t parts \u003d [p.strip() for p in text.split(\"||\") if p.strip()]\n\t \n\t # Build instance dictionaries\n\t for p in parts:\n\t items.append({\n\t \"instanceStyle\": {},\n\t \"instancePosition\": {},\n\t \"text\": p\n\t })\n\texcept Exception as e:\n\t system.perspective.print(\"FaultItem repeater transform error: \" + str(e))\n\t items \u003d []\n\t\n\treturn items", + "type": "script" + } + ], + "type": "tag" + }, + "persistent": true + }, + "custom.faultRemedy": { + "binding": { + "config": { + "fallbackDelay": 2.5, + "mode": "indirect", + "references": { + "0": "{view.params.tagProps[0]}", + "fc": "{session.custom.fc}" + }, + "tagPath": "[{fc}_SCADA_TAG_PROVIDER]{0}/Fault/Fault_Remedy" + }, + "transforms": [ + { + "expression": "coalesce({value},\"\")", + "type": "expression" + }, + { + "code": "\t# Input: a string like \"Ambient temperature too high. || Fan or ventilation slots are polluted. || Fan is defective.\"\n\t# Output: a list of instance dicts for the repeater\n\t\n\titems \u003d []\n\t\n\ttry:\n\t text \u003d str(value).strip()\n\t if text:\n\t # Split by \"||\" and clean up\n\t parts \u003d [p.strip() for p in text.split(\"||\") if p.strip()]\n\t \n\t # Build instance dictionaries\n\t for p in parts:\n\t items.append({\n\t \"instanceStyle\": {},\n\t \"instancePosition\": {},\n\t \"text\": p\n\t })\n\texcept Exception as e:\n\t system.perspective.print(\"FaultItem repeater transform error: \" + str(e))\n\t items \u003d []\n\t\n\treturn items", + "type": "script" + } + ], + "type": "tag" + }, + "persistent": true + }, "custom.fpm": { "binding": { "config": { @@ -274,6 +387,7 @@ }, "props": { "defaultSize": { + "height": 1080, "width": 600 } }, @@ -935,7 +1049,7 @@ "height": 161, "width": 98, "x": 97.65, - "y": 505.33000000000004 + "y": 455.33 }, "propConfig": { "props.style.backgroundColor": { @@ -975,7 +1089,7 @@ "height": 92, "width": 314, "x": 205.65, - "y": 505.30999999999995 + "y": 455.31 }, "propConfig": { "props.style.backgroundColor": { @@ -1015,7 +1129,7 @@ "height": 64, "width": 98, "x": 205.296, - "y": 602.3 + "y": 552.3 }, "propConfig": { "props.enabled": { @@ -1063,7 +1177,7 @@ "height": 64, "width": 98, "x": 314.65, - "y": 602.29 + "y": 552.29 }, "propConfig": { "props.enabled": { @@ -1111,7 +1225,7 @@ "height": 64, "width": 98, "x": 421.296, - "y": 602.249 + "y": 552.249 }, "propConfig": { "props.enabled": { @@ -1259,6 +1373,231 @@ "y": 381.49 }, "type": "ia.container.flex" + }, + { + "children": [ + { + "meta": { + "name": "Label" + }, + "position": { + "basis": "32px" + }, + "propConfig": { + "props.text": { + "binding": { + "config": { + "expression": "\"LENZE FAULTED : \" + {view.custom.faultDescription}" + }, + "type": "expr" + } + } + }, + "props": { + "style": { + "color": "black", + "paddingLeft": "20px" + } + }, + "type": "ia.display.label" + }, + { + "children": [ + { + "children": [ + { + "meta": { + "name": "Label" + }, + "position": { + "basis": "33px", + "shrink": 0 + }, + "props": { + "style": { + "background": "#d9d9d9", + "color": "#000000" + }, + "text": "Cause", + "textStyle": { + "textAlign": "center" + } + }, + "type": "ia.display.label" + }, + { + "children": [ + { + "meta": { + "name": "FlexRepeater" + }, + "position": { + "basis": "100%" + }, + "propConfig": { + "props.instances": { + "binding": { + "config": { + "path": "view.custom.faultProbableCause" + }, + "type": "property" + } + } + }, + "props": { + "direction": "column", + "path": "autStand/Equipment/VFD-Views/FaultItem", + "style": { + "overflowX": "hidden" + }, + "useDefaultViewWidth": false + }, + "type": "ia.display.flex-repeater" + } + ], + "meta": { + "name": "FlexContainer" + }, + "position": { + "basis": "200px", + "grow": 1 + }, + "props": { + "direction": "column", + "style": { + "borderRight": "solid black 0.5px", + "overflow": "visible" + } + }, + "type": "ia.container.flex" + } + ], + "meta": { + "name": "FlexContainer" + }, + "position": { + "basis": "277px" + }, + "props": { + "direction": "column" + }, + "type": "ia.container.flex" + }, + { + "children": [ + { + "meta": { + "name": "Label" + }, + "position": { + "basis": "33px", + "shrink": 0 + }, + "props": { + "style": { + "background": "#d9d9d9", + "color": "#000000" + }, + "text": "Remedy", + "textStyle": { + "textAlign": "center" + } + }, + "type": "ia.display.label" + }, + { + "children": [ + { + "meta": { + "name": "FlexRepeater" + }, + "position": { + "basis": "100%" + }, + "propConfig": { + "props.instances": { + "binding": { + "config": { + "path": "view.custom.faultRemedy" + }, + "type": "property" + } + } + }, + "props": { + "direction": "column", + "path": "autStand/Equipment/VFD-Views/FaultItem", + "style": { + "overflowX": "hidden" + }, + "useDefaultViewWidth": false + }, + "type": "ia.display.flex-repeater" + } + ], + "meta": { + "name": "FlexContainer" + }, + "position": { + "basis": "200px", + "grow": 1 + }, + "props": { + "direction": "column", + "style": { + "overflow": "visible" + } + }, + "type": "ia.container.flex" + } + ], + "meta": { + "name": "FlexContainer_0" + }, + "position": { + "basis": "277px" + }, + "props": { + "direction": "column", + "style": { + "borderLeft": "solid black 0.5px" + } + }, + "type": "ia.container.flex" + } + ], + "meta": { + "name": "FlexContainer_8" + }, + "position": { + "grow": 1 + }, + "type": "ia.container.flex" + } + ], + "meta": { + "name": "FlexContainer_2" + }, + "position": { + "height": 300, + "width": 508, + "x": 42.33000093823242, + "y": 642.33 + }, + "propConfig": { + "meta.visible": { + "binding": { + "config": { + "expression": "{view.custom.faultDescription} !\u003d \"\"" + }, + "type": "expr" + } + } + }, + "props": { + "direction": "column" + }, + "type": "ia.container.flex" } ], "meta": { diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Beacon/resource.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Beacon/resource.json index a7d38e26..0b44c341 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Beacon/resource.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Beacon/resource.json @@ -9,8 +9,8 @@ "attributes": { "lastModification": { "actor": "admin", - "timestamp": "2025-11-05T10:03:20Z" + "timestamp": "2025-11-05T10:58:14Z" }, - "lastModificationSignature": "a45fc778e3455652a14c8b77b8c627633086bef4b0984bff774dc9ebdf86e057" + "lastModificationSignature": "71bfb1fcb21970bcad2d212abf101e99ef7649061deac3f5f19a56201c32172e" } } \ No newline at end of file diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Beacon/view.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Beacon/view.json index 27de9c16..ec71ac13 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Beacon/view.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Beacon/view.json @@ -3,7 +3,7 @@ "beacon": 0, "flashingColor": "#808080", "solidColor": "#FF8C00", - "state": "Offline" + "state": "OFF" }, "params": { "demoColor": "", diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Button/resource.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Button/resource.json index c5857bf2..70324b0c 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Button/resource.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Button/resource.json @@ -10,8 +10,8 @@ "attributes": { "lastModification": { "actor": "admin", - "timestamp": "2025-11-05T10:09:30Z" + "timestamp": "2025-11-05T10:58:25Z" }, - "lastModificationSignature": "202804489dea1be0a5952a0a0668d47e8996b586217d8ad06b5d35301a270f64" + "lastModificationSignature": "e589663e9d0f7b86bd955fa5f896c4baf8f4a5aac6054a89087b606e53e849e4" } } \ No newline at end of file diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Button/view.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Button/view.json index 57218d35..5eef58ec 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Button/view.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Button/view.json @@ -3,7 +3,7 @@ "color": "#000000", "deviceName": "S03_1_JR1", "priority": "No Active Alarms", - "state": "Offline" + "state": "Actuated" }, "params": { "demoColor": -1, diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Chute_Button/resource.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Chute_Button/resource.json index 5089c4b3..36f79344 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Chute_Button/resource.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Chute_Button/resource.json @@ -10,8 +10,8 @@ "attributes": { "lastModification": { "actor": "admin", - "timestamp": "2025-11-05T10:03:48Z" + "timestamp": "2025-11-05T10:58:14Z" }, - "lastModificationSignature": "c0cad2fb0a077cee13c61f73d4e2698972da4e4f0919e1dc8186d33ccb57d204" + "lastModificationSignature": "0d465364c45191827e9b2d189ed92b7134de40f76d8b257abb57acb6ce25c269" } } \ No newline at end of file diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Chute_Button/view.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Chute_Button/view.json index a756e355..19050170 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Chute_Button/view.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Chute_Button/view.json @@ -3,7 +3,7 @@ "color": "#000000", "deviceName": "S03_CH115_EN", "priority": "No Active Alarms", - "state": "Offline" + "state": "Closed" }, "params": { "demoColor": -1, diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Controller-Views/CommandControlAlarms/resource.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Controller-Views/CommandControlAlarms/resource.json index 3345ecc0..fe6d9cc5 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Controller-Views/CommandControlAlarms/resource.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Controller-Views/CommandControlAlarms/resource.json @@ -10,8 +10,8 @@ "attributes": { "lastModification": { "actor": "admin", - "timestamp": "2025-11-03T10:48:14Z" + "timestamp": "2025-11-06T09:45:29Z" }, - "lastModificationSignature": "e4adadbb2ccaa998f6711c2f1835a11716490fb19c8407ca298fb9f3f7f4ae71" + "lastModificationSignature": "a7f4a48b3b1044a614c495a7abbb5fc64daa1bd6fa748696d30ff0d6c61e4409" } } \ No newline at end of file diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Controller-Views/CommandControlAlarms/view.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Controller-Views/CommandControlAlarms/view.json index c2e2930c..5918c4b7 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Controller-Views/CommandControlAlarms/view.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Controller-Views/CommandControlAlarms/view.json @@ -3,16 +3,16 @@ "counts": { "Critical": 0, "Diagnostic": 0, - "High": 20, - "Low": 5, - "Medium": 2, - "Total": 27 + "High": 6, + "Low": 2, + "Medium": 1, + "Total": 9 }, "totalAlarms": { "$": [ "ds", 192, - 1762166890980 + 1762422326706 ], "$columns": [ { @@ -39,11 +39,11 @@ }, { "data": [ - 20, - 5, + 6, 2, - 36, - 3 + 1, + 32, + 4 ], "name": "Count", "type": "Long" diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Controller-Views/CommandControlStatus/resource.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Controller-Views/CommandControlStatus/resource.json index 04b6e9f5..4f3036ca 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Controller-Views/CommandControlStatus/resource.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Controller-Views/CommandControlStatus/resource.json @@ -10,8 +10,8 @@ "attributes": { "lastModification": { "actor": "admin", - "timestamp": "2025-11-03T10:48:13Z" + "timestamp": "2025-11-06T09:45:28Z" }, - "lastModificationSignature": "cf6029c178a1897c4e3745df0737345d13ee88bf22deb4eba98b83aba636794d" + "lastModificationSignature": "caef4a008da4d1c2473f73bb35520e0a7f394b4a25cb5947098e0dd928cf5dee" } } \ No newline at end of file diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Controller-Views/CommandControlStatus/view.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Controller-Views/CommandControlStatus/view.json index 5aa45ce7..c79fd876 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Controller-Views/CommandControlStatus/view.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Controller-Views/CommandControlStatus/view.json @@ -4,7 +4,7 @@ "$": [ "ds", 192, - 1762166893089 + 1762422327752 ], "$columns": [ { @@ -31,11 +31,11 @@ }, { "data": [ - 20, - 5, + 6, 2, - 36, - 3 + 1, + 32, + 4 ], "name": "Count", "type": "Long" diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Controller-Views/ControllerStatus/resource.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Controller-Views/ControllerStatus/resource.json index ffc306a8..bb28de84 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Controller-Views/ControllerStatus/resource.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Controller-Views/ControllerStatus/resource.json @@ -10,8 +10,8 @@ "attributes": { "lastModification": { "actor": "admin", - "timestamp": "2025-11-03T10:45:14Z" + "timestamp": "2025-11-06T09:28:00Z" }, - "lastModificationSignature": "905f499557e14f9a6ba14b18a8f3a8a99087be92b0ad57a907532cd840a2efea" + "lastModificationSignature": "33a2d01b5e1831e82442481afd4cfaa270b9e4136809c9c6711b8d1272c54167" } } \ No newline at end of file diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Controller-Views/ControllerStatus/view.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Controller-Views/ControllerStatus/view.json index b48fea96..33f80aba 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Controller-Views/ControllerStatus/view.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Controller-Views/ControllerStatus/view.json @@ -443,7 +443,7 @@ "basis": "32px" }, "props": { - "text": 20, + "text": 6, "textStyle": { "fontSize": 10, "textAlign": "center" @@ -472,7 +472,7 @@ "basis": "32px" }, "props": { - "text": 2, + "text": 1, "textStyle": { "fontSize": 10, "textAlign": "center" @@ -501,7 +501,7 @@ "basis": "32px" }, "props": { - "text": 5, + "text": 2, "textStyle": { "fontSize": 10, "textAlign": "center" @@ -559,7 +559,7 @@ "basis": "32px" }, "props": { - "text": 27, + "text": 9, "textStyle": { "fontSize": 10, "textAlign": "center" @@ -625,9 +625,9 @@ "counts": { "Critical": 0, "Diagnostic": 0, - "High": 20, - "Low": 5, - "Medium": 2 + "High": 6, + "Low": 2, + "Medium": 1 } }, "events": { diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Conveyor45/resource.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Conveyor45/resource.json index 62ac0b24..6fe059f8 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Conveyor45/resource.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Conveyor45/resource.json @@ -10,8 +10,8 @@ "attributes": { "lastModification": { "actor": "admin", - "timestamp": "2025-11-05T10:04:41Z" + "timestamp": "2025-11-06T05:53:32Z" }, - "lastModificationSignature": "c3053fd47ba6060f90c82b968094d2ad57a40bc60e1a63de3439b5bca745bda2" + "lastModificationSignature": "09a417e495e942ce0d88518e9bbbe1e80703111c87e5b1c709b329fb4aecb0a9" } } \ No newline at end of file diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Conveyor45/view.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Conveyor45/view.json index 29293920..e9595ea6 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Conveyor45/view.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Conveyor45/view.json @@ -571,7 +571,7 @@ "dom": { "onClick": { "config": { - "script": "\t#create devices and tags lists for the conveyor\n\tprops \u003d self.view.params.tagProps[0]\n\tautStand.devices.build_device_mapping(props)\n\tdevice_table_dataset \u003d autStand.devices.build_device_table(self)\n\ttags_table_dataset \u003d autStand.devices.getAllTags(self, props)\n\tsystem.perspective.openDock(\u0027Docked-East-Conv\u0027,params\u003d{\u0027tagProps\u0027:self.view.params.tagProps, \"devices\": device_table_dataset, \"tags\":tags_table_dataset})" + "script": "\t#create devices and tags lists for the conveyor\n\tprops \u003d self.view.params.tagProps[0]\n\tautStand.devices.build_device_mapping(props)\n\tdevice_table_dataset \u003d autStand.devices.build_device_table(self)\n\ttags_table_dataset \u003d autStand.devices.getAllTags(self, props, section \u003d \"conveyor\")\n\tsystem.perspective.openDock(\u0027Docked-East-Conv\u0027,params\u003d{\u0027tagProps\u0027:self.view.params.tagProps, \"devices\": device_table_dataset, \"tags\":tags_table_dataset})" }, "scope": "G", "type": "script" diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Conveyor_Left90/resource.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Conveyor_Left90/resource.json index 3691436a..0794290f 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Conveyor_Left90/resource.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Conveyor_Left90/resource.json @@ -10,8 +10,8 @@ "attributes": { "lastModification": { "actor": "admin", - "timestamp": "2025-11-05T10:05:09Z" + "timestamp": "2025-11-06T05:53:39Z" }, - "lastModificationSignature": "11f6963d22782647abcea15e4264ecba09836177042468b2d2cb434715c4ae1e" + "lastModificationSignature": "922086cbe69562d7e45d7d20f33be2d8f41991e47ae7e6a280195f0e92b4d23a" } } \ No newline at end of file diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Conveyor_Left90/view.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Conveyor_Left90/view.json index 5db94a0f..45ad6482 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Conveyor_Left90/view.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Conveyor_Left90/view.json @@ -594,7 +594,7 @@ "dom": { "onClick": { "config": { - "script": "\t#create devices and tags lists for the conveyor\n\tprops \u003d self.view.params.tagProps[0]\n\tautStand.devices.build_device_mapping(props)\n\tdevice_table_dataset \u003d autStand.devices.build_device_table(self)\n\ttags_table_dataset \u003d autStand.devices.getAllTags(self, props)\n\tsystem.perspective.openDock(\u0027Docked-East-Conv\u0027,params\u003d{\u0027tagProps\u0027:self.view.params.tagProps, \"devices\": device_table_dataset, \"tags\":tags_table_dataset})" + "script": "\t#create devices and tags lists for the conveyor\n\tprops \u003d self.view.params.tagProps[0]\n\tautStand.devices.build_device_mapping(props)\n\tdevice_table_dataset \u003d autStand.devices.build_device_table(self)\n\ttags_table_dataset \u003d autStand.devices.getAllTags(self, props, section \u003d \"conveyor\")\n\tsystem.perspective.openDock(\u0027Docked-East-Conv\u0027,params\u003d{\u0027tagProps\u0027:self.view.params.tagProps, \"devices\": device_table_dataset, \"tags\":tags_table_dataset})" }, "scope": "G", "type": "script" diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Conveyor_Right90/resource.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Conveyor_Right90/resource.json index 85860aec..6028f6ae 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Conveyor_Right90/resource.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Conveyor_Right90/resource.json @@ -10,8 +10,8 @@ "attributes": { "lastModification": { "actor": "admin", - "timestamp": "2025-11-05T10:05:46Z" + "timestamp": "2025-11-06T05:53:46Z" }, - "lastModificationSignature": "66e4286fd9730511928ddcf22341e9cf8d36aac0f861b6a32011597ee1e93490" + "lastModificationSignature": "41eb3b4d3418906754d43553be1845cdd7ccd9841a13e983b4f290d6e6247e8a" } } \ No newline at end of file diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Conveyor_Right90/view.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Conveyor_Right90/view.json index f5e9dc9c..11e599ed 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Conveyor_Right90/view.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Conveyor_Right90/view.json @@ -574,7 +574,7 @@ "dom": { "onClick": { "config": { - "script": "\t#create devices and tags lists for the conveyor\n\tprops \u003d self.view.params.tagProps[0]\n\tautStand.devices.build_device_mapping(props)\n\tdevice_table_dataset \u003d autStand.devices.build_device_table(self)\n\ttags_table_dataset \u003d autStand.devices.getAllTags(self, props)\n\tsystem.perspective.openDock(\u0027Docked-East-Conv\u0027,params\u003d{\u0027tagProps\u0027:self.view.params.tagProps, \"devices\": device_table_dataset, \"tags\":tags_table_dataset})" + "script": "\t#create devices and tags lists for the conveyor\n\tprops \u003d self.view.params.tagProps[0]\n\tautStand.devices.build_device_mapping(props)\n\tdevice_table_dataset \u003d autStand.devices.build_device_table(self)\n\ttags_table_dataset \u003d autStand.devices.getAllTags(self, props, section \u003d \"conveyor\")\n\tsystem.perspective.openDock(\u0027Docked-East-Conv\u0027,params\u003d{\u0027tagProps\u0027:self.view.params.tagProps, \"devices\": device_table_dataset, \"tags\":tags_table_dataset})" }, "scope": "G", "type": "script" diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Photoeye_Long/resource.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Photoeye_Long/resource.json index 3028e109..db725565 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Photoeye_Long/resource.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Photoeye_Long/resource.json @@ -10,8 +10,8 @@ "attributes": { "lastModification": { "actor": "admin", - "timestamp": "2025-11-05T09:56:58Z" + "timestamp": "2025-11-05T16:03:12Z" }, - "lastModificationSignature": "47cb76182cad0ebbd030abdd3997bfc6c5031f7b3111d9378e0ec295e06995f3" + "lastModificationSignature": "af732729fae7c59783c445521081d73eb607e4723fe1070097c979d25a5dd1e1" } } \ No newline at end of file diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Photoeye_Tracking/resource.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Photoeye_Tracking/resource.json index 76ccaa58..b5f80e1e 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Photoeye_Tracking/resource.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Photoeye_Tracking/resource.json @@ -10,8 +10,8 @@ "attributes": { "lastModification": { "actor": "admin", - "timestamp": "2025-11-05T09:56:37Z" + "timestamp": "2025-11-05T11:04:37Z" }, - "lastModificationSignature": "73ef999335872207376b4932914dc91ce58ac2e266a384a16d2ed0679307a363" + "lastModificationSignature": "2967f9a672eda98f9b5149d0d6037ce4870a5c4458a77de30f302c5d94a0cb81" } } \ No newline at end of file diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Photoeye_Tracking/view.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Photoeye_Tracking/view.json index 30fe0f98..5db0b6bc 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Photoeye_Tracking/view.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Photoeye_Tracking/view.json @@ -4,7 +4,7 @@ "isHighlited": false, "overlayColor": "#ffffff", "priority": "No Active Alarms", - "state": "Offline" + "state": "BLOCKED" }, "params": { "demoColor": -1, diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/ProxSensor/resource.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/ProxSensor/resource.json index a61f5cdd..2db56fef 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/ProxSensor/resource.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/ProxSensor/resource.json @@ -10,8 +10,8 @@ "attributes": { "lastModification": { "actor": "admin", - "timestamp": "2025-11-05T09:55:47Z" + "timestamp": "2025-11-05T11:02:12Z" }, - "lastModificationSignature": "e499dac6c15ef5769b713f487a901f89ddded7480c634bec50783348ccd686ad" + "lastModificationSignature": "e62e71b2c3c31d9b02ac9ae66a4e5a4858c85d9bb78bdc1beb5ca56be7eb8a90" } } \ No newline at end of file diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/ProxSensor/view.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/ProxSensor/view.json index b1fd0d16..cb91a123 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/ProxSensor/view.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/ProxSensor/view.json @@ -1,8 +1,8 @@ { "custom": { - "color": "#000000", + "color": "#AAAAAA", "deviceName": "S03_CH101_PRX1", - "state": "Offline" + "state": "INACTIVE" }, "params": { "demoColor": -1, diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Solenoid/resource.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Solenoid/resource.json index e4c0e9af..20d23076 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Solenoid/resource.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Solenoid/resource.json @@ -10,8 +10,8 @@ "attributes": { "lastModification": { "actor": "admin", - "timestamp": "2025-11-05T09:50:17Z" + "timestamp": "2025-11-05T10:58:14Z" }, - "lastModificationSignature": "00481db9366a0ae0a8ca6bea529f685857c34990822f5aa2f60b42c12400148b" + "lastModificationSignature": "e439249b233a0322cf68a4b7c22d5871ff1adf0d75c7b265d487f4f564ff9009" } } \ No newline at end of file diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Solenoid/view.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Solenoid/view.json index 01b492f2..4eea33d0 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Solenoid/view.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/Solenoid/view.json @@ -4,7 +4,7 @@ "divertingLeft": false, "divertingRight": false, "priority": "No Active Alarms", - "state": "Offline" + "state": "Closed" }, "params": { "demoColor": 0, diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/VFD-Views/FaultItem/resource.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/VFD-Views/FaultItem/resource.json new file mode 100644 index 00000000..7645ca0a --- /dev/null +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/VFD-Views/FaultItem/resource.json @@ -0,0 +1,17 @@ +{ + "scope": "G", + "version": 1, + "restricted": false, + "overridable": true, + "files": [ + "view.json", + "thumbnail.png" + ], + "attributes": { + "lastModification": { + "actor": "admin", + "timestamp": "2025-11-06T10:41:41Z" + }, + "lastModificationSignature": "94ada3882d5e031e352abc0f63fdb45b43f2491a46298cbcded7dcb4468f6367" + } +} \ No newline at end of file diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/VFD-Views/FaultItem/thumbnail.png b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/VFD-Views/FaultItem/thumbnail.png new file mode 100644 index 00000000..0dc9abde Binary files /dev/null and b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/VFD-Views/FaultItem/thumbnail.png differ diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/VFD-Views/FaultItem/view.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/VFD-Views/FaultItem/view.json new file mode 100644 index 00000000..b5a2c4ff --- /dev/null +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/VFD-Views/FaultItem/view.json @@ -0,0 +1,77 @@ +{ + "custom": {}, + "params": { + "text": "Provide for a sufficient cooling of the device." + }, + "propConfig": { + "params.text": { + "paramDirection": "input", + "persistent": true + } + }, + "props": { + "defaultSize": { + "height": 50, + "width": 300 + } + }, + "root": { + "children": [ + { + "meta": { + "name": "Icon" + }, + "position": { + "basis": "20px", + "shrink": 0 + }, + "props": { + "path": "material/brightness_1", + "style": { + "color": "black", + "marginLeft": 4, + "marginTop": 4 + } + }, + "type": "ia.display.icon" + }, + { + "meta": { + "name": "Label" + }, + "position": { + "grow": 1 + }, + "propConfig": { + "props.text": { + "binding": { + "config": { + "path": "view.params.text" + }, + "type": "property" + } + } + }, + "props": { + "textStyle": { + "color": "black", + "fontSize": "18px" + } + }, + "type": "ia.display.label" + } + ], + "meta": { + "name": "root" + }, + "props": { + "alignContent": "center", + "alignItems": "flex-start", + "justify": "space-evenly", + "style": { + "gap": 7 + } + }, + "type": "ia.container.flex" + } +} \ No newline at end of file diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/VFD/resource.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/VFD/resource.json index ff180525..14806de5 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/VFD/resource.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/VFD/resource.json @@ -10,8 +10,8 @@ "attributes": { "lastModification": { "actor": "admin", - "timestamp": "2025-11-05T09:49:59Z" + "timestamp": "2025-11-06T09:34:59Z" }, - "lastModificationSignature": "eb4e651526b151add3fe79e7c2cc150331f570ba01f258f74f9960ce062abc28" + "lastModificationSignature": "a03070e098038bd2aa62a5692f809f523c8cdbc858d38157421e0a19292a0a79" } } \ No newline at end of file diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/VFD/view.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/VFD/view.json index 99f00a58..f53ab0be 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/VFD/view.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/Equipment/VFD/view.json @@ -1,6 +1,6 @@ { "custom": { - "color": "#000", + "color": "#f9050d", "modifiedTag": "System/MCM01/VFD/UL14_1_VFD1", "priority": "No Active Alarms" }, diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/PopUp-Views/Legend_Popup/Legend-DOO/resource.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/PopUp-Views/Legend_Popup/Legend-DOO/resource.json index d130b595..4871f6b4 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/PopUp-Views/Legend_Popup/Legend-DOO/resource.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/PopUp-Views/Legend_Popup/Legend-DOO/resource.json @@ -10,8 +10,8 @@ "attributes": { "lastModification": { "actor": "admin", - "timestamp": "2025-11-03T07:30:59Z" + "timestamp": "2025-11-06T09:10:53Z" }, - "lastModificationSignature": "6a0fecdc30b481e27569e24c81a59df066b326c50e14d901e82490fe84307fed" + "lastModificationSignature": "f3c965334dd56490910cdc0493c176ee8dd58074925b58c32317a373fa271897" } } \ No newline at end of file diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/PopUp-Views/Legend_Popup/Legend-DOO/thumbnail.png b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/PopUp-Views/Legend_Popup/Legend-DOO/thumbnail.png index fb0f0175..ca12e795 100644 Binary files a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/PopUp-Views/Legend_Popup/Legend-DOO/thumbnail.png and b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/PopUp-Views/Legend_Popup/Legend-DOO/thumbnail.png differ diff --git a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/PopUp-Views/Legend_Popup/Legend-DOO/view.json b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/PopUp-Views/Legend_Popup/Legend-DOO/view.json index 0b308663..a5024aa1 100644 --- a/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/PopUp-Views/Legend_Popup/Legend-DOO/view.json +++ b/BNA8_autStand/com.inductiveautomation.perspective/views/autStand/PopUp-Views/Legend_Popup/Legend-DOO/view.json @@ -3,7 +3,7 @@ "params": {}, "props": { "defaultSize": { - "height": 1000 + "height": 920 } }, "root": { diff --git a/BNA8_autStand/ignition/script-python/autStand/devices/code.py b/BNA8_autStand/ignition/script-python/autStand/devices/code.py index 90573ef3..f2ef9571 100644 --- a/BNA8_autStand/ignition/script-python/autStand/devices/code.py +++ b/BNA8_autStand/ignition/script-python/autStand/devices/code.py @@ -1,308 +1,542 @@ import os, json, sys +# ====================================================== +# Helper Function: State Resolver +# ====================================================== +def get_device_state(value, tagPath): + up = tagPath.upper() + + # === Base state dictionary === + state_mappings = { + 0: "Closed", + 1: "Actuated", + 2: "Communication Faulted", + 3: "Conveyor Running In Maintenance Mode", + 4: "Disabled", + 5: "Disconnected", + 6: "Stopped", + 7: "Enabled Not Running", + 8: "Encoder Fault", + 9: "Energy Management", + 10: "ESTOP Was Actuated", + 11: "EStopped", + 12: "EStopped Locally", + 13: "Extended Faulted", + 14: "Full", + 15: "Gaylord Start Pressed", + 16: "Jam Fault", + 17: "Jammed", + 18: "Loading Allowed", + 19: "Loading Not Allowed", + 20: "Low Air Pressure Fault Was Present", + 21: "Maintenance Mode", + 22: "Conveyor Stopped In Maintenance Mode", + 23: "Motor Faulted", + 24: "Motor Was Faulted", + 25: "Normal", + 26: "Off Inactive", + 27: "Open", + 28: "PLC Ready To Run", + 29: "Package Release Pressed", + 30: "Power Branch Was Faulted", + 31: "Pressed", + 32: "Ready To Receive", + 33: "Running", + 34: "Started", + 35: "Stopped", + 36: "System Started", + 37: "Unknown", + 38: "VFD Fault", + 39: "Conveyor Running In Power Saving Mode", + 40: "Conveyor Jogging In Maintenance Mode", + 41: "VFD Reset Required", + 42: "Jam Reset Push Button Pressed", + 43: "Start Push Button Pressed", + 44: "Stop Push Button Pressed", + 45: "No Container", + 46: "Ready To Be Enabled", + 47: "Half Full", + 48: "Enabled", + 49: "Tipper Faulted", + 50: "OK", + 51: "Disconnected", + 52: "Faulted", + 53: "Faulted/Disconnect", + 54: "Diverting" + } + + # === TPE (Tracking Photoeye) === + if "/TPE/" in up: + if value == 0: + return "Blocked" + elif value == 27: + return "Clear" + elif value == 17: + return "Jammed" + else: + return state_mappings.get(value, "Unknown") + + # === Single Photoeyes (PE1, PE2) === + if up.endswith(("PE1", "PE2")): + if not value: + return "Clear" + else: + return "Blocked" + + # === Prox Sensors (PRX1, PRX2) === + if up.endswith(("PRX1", "PRX2")): + if not value: + return "Inactive" + else: + return "Actuated" + + # === Beacons (BCN) === + if "/BEACON" in up: + if value == 0: + return "Off" + elif value == 1: + return "Cleared / Reset Required" + else: + return "Active" + + # === Default === + return state_mappings.get(value, "Unknown") + + +# ====================================================== +# Helper Function: Read One Device (multi or single state) +# ====================================================== +def read_device_status(tagPath, provider, dev_name): + """ + Reads the appropriate state tag(s) for a given device and returns + a list of {Device, Status} dictionaries. + Handles multi-state (SS), VFD, PRX, PE, EN, etc. + """ + rows = [] + try: + up = tagPath.upper() + + # === Case 0: SS (Start/Stop Station) === + if up.endswith("SS") or "/SS/" in up: + for sub in ("Start", "Stop"): + sub_path = provider + tagPath + "/" + sub + "/State" + try: + result = system.tag.readBlocking([sub_path])[0] + if result.quality.isGood(): + status_value = get_device_state(result.value, tagPath) + else: + status_value = "Unknown" + except: + status_value = "Unknown" + + rows.append({ + "Device": "{} ({})".format(dev_name, sub), + "Status": status_value + }) + return rows # handled fully + + # === Case 1: VFD / Conveyor === + if "/VFD/" in up: + path = provider + tagPath + "/Drive/Lenze" + + # === Case 2: Chute sensors (PE / PRX) === + elif up.endswith(("PE1", "PE2", "PRX1", "PRX2")) and "/TPE/" not in up: + path = provider + tagPath + + # === Case 3: Chute EN === + elif up.endswith("EN") and "/CHUTE/" in up: + path = provider + tagPath + "_State" + + # === Case 4: Default === + else: + path = provider + tagPath + "/State" + + try: + result = system.tag.readBlocking([path])[0] + if result.quality.isGood(): + status_value = get_device_state(result.value, tagPath) + else: + status_value = "Offline" + except: + status_value = "Offline" + + rows.append({ + "Device": dev_name, + "Status": status_value + }) + + except Exception as e: + system.perspective.print("Error reading device status for %s: %s" % (dev_name, e)) + + return rows + + +# ====================================================== +# Helper Function: Single Device Reader (for Docked Device View) +# ====================================================== +def get_single_device_status(self, tagPath): + """ + Reads a single device tag (used for docked device views). + Returns a single readable status string (e.g. "Running", "Blocked", etc.) + """ + try: + up = tagPath.upper() + provider = "[" + self.session.custom.fc + "_SCADA_TAG_PROVIDER]" + + if up.endswith("SS") or "/SS/" in up: + states = [] + for sub in ("Start", "Stop"): + sub_path = provider + tagPath + "/" + sub + "/State" + try: + result = system.tag.readBlocking([sub_path])[0] + if result.quality.isGood(): + states.append("{}: {}".format(sub, get_device_state(result.value, tagPath))) + else: + states.append("{}: Unknown".format(sub)) + except: + states.append("{}: Unknown".format(sub)) + return " | ".join(states) + + # === VFD === + if "/VFD/" in up: + path = provider + tagPath + "/Drive/Lenze" + # === Sensors === + elif up.endswith(("PE1", "PE2", "PRX1", "PRX2")) and "/TPE/" not in up: + path = provider + tagPath + # === EN === + elif up.endswith("EN") and "/CHUTE/" in up: + path = provider + tagPath + "_State" + else: + path = provider + tagPath + "/State" + + result = system.tag.readBlocking([path])[0] + if result.quality.isGood(): + return get_device_state(result.value, tagPath) + else: + return "Unknown" + + except Exception as e: + system.perspective.print("Error reading single device status for %s: %s" % (tagPath, e)) + return "Unknown" + + +# ====================================================== +# Device Mapping Builder +# ====================================================== global_device_mapping = {} def build_device_mapping(full_tag_path): - """ - Builds global_device_mapping for devices that: - - Belong to the same PLC (index 1) - - Are children of the clicked device (start with clicked_name + "_") - """ - global global_device_mapping - global_device_mapping.clear() - - + """ + Builds global_device_mapping for devices under the same PLC and parent device. + Adds support for: + - Chute FIOM devices (e.g. S03_CH109_FIOM_1 when clicking S03_CH109) + - Shared JR and PE devices used by multiple chutes (e.g. S03_1_JR1, S03_1_LRPE1) + """ + system.perspective.print(full_tag_path) + global global_device_mapping + global_device_mapping.clear() - try: - # Parse PLC and clicked device - path_parts = full_tag_path.split("/") - plc_name = path_parts[1] if len(path_parts) > 1 else path_parts[0] - clicked_name = path_parts[-1] if len(path_parts) > 0 else "" - if "_VFD" in clicked_name: - idx = clicked_name.find("_VFD") - if idx != -1: - clicked_name = clicked_name[:idx] + try: + path_parts = full_tag_path.split("/") + plc_name = path_parts[1] if len(path_parts) > 1 else path_parts[0] + clicked_name = path_parts[-1] if len(path_parts) > 0 else "" - project_name = system.util.getProjectName() - base_path = ( - os.getcwd().replace("\\", "/") - + "/data/projects/" - + project_name - + "/com.inductiveautomation.perspective/Views/autStand/Detailed_Views/MCM-Views" - ) + # --- Clean clicked name --- + if "_VFD" in clicked_name: + clicked_name = clicked_name.split("_VFD")[0] - if not os.path.exists(base_path): - system.perspective.print("Path not found: " + base_path) - return {} + project_name = system.util.getProjectName() + base_path = ( + os.getcwd().replace("\\", "/") + + "/data/projects/" + + project_name + + "/com.inductiveautomation.perspective/Views/autStand/Detailed_Views/MCM-Views" + ) - # loop through all view folders - for view_folder in os.listdir(base_path): - json_file = os.path.join(base_path, view_folder, "view.json") - if not os.path.isfile(json_file): - continue + if not os.path.exists(base_path): + system.perspective.print("Path not found: " + base_path) + return {} - try: - with open(json_file, "r") as fh: - view_json = json.load(fh) - except Exception: - continue + # --- Detect if this is a Chute --- + is_chute = "/CHUTE/" in full_tag_path.upper() - # go one level deeper: root -> children[0] (coordinateContainer) -> its children - root_children = (view_json.get("root") or {}).get("children") or [] - if not root_children: - continue + for view_folder in os.listdir(base_path): + json_file = os.path.join(base_path, view_folder, "view.json") + if not os.path.isfile(json_file): + continue - container = root_children[0] - children = container.get("children") or [] + try: + with open(json_file, "r") as fh: + view_json = json.load(fh) + except Exception: + continue - for child in children: - props = child.get("props") or {} - params = props.get("params") or {} - tag_props = params.get("tagProps") + root_children = (view_json.get("root") or {}).get("children") or [] + if not root_children: + continue - if isinstance(tag_props, list) and len(tag_props) > 0: - tag_prop = str(tag_props[0]) - parts = tag_prop.split("/") + container = root_children[0] + children = container.get("children") or [] - if len(parts) > 1 and parts[1] == plc_name: - - dev_name = parts[-1] - if len(parts) > 3 and parts[-2] == clicked_name: - dev_name = clicked_name + "_" + parts[-1] - system.perspective.print(dev_name) + for child in children: + props = child.get("props") or {} + params = props.get("params") or {} + tag_props = params.get("tagProps") - # ONLY include devices that are children of clicked_name - else: - dev_name = parts[-1] - prefix = clicked_name + "_" - - if dev_name.startswith(prefix) or (len(parts) > 3 and parts[-2] == clicked_name): - global_device_mapping[dev_name] = { - "tagPath": tag_prop, - "zone": view_folder - } - - return global_device_mapping + if isinstance(tag_props, list) and len(tag_props) > 0: + tag_prop = str(tag_props[0]) + parts = tag_prop.split("/") - except Exception as e: - whid = "unknown" - try: - whid = system.tag.readBlocking("Configuration/FC")[0].value - except: - pass - logger = system.util.getLogger("%s-build_device_mapping" % whid) - exc_type, exc_obj, tb = sys.exc_info() - logger.error("Error at line %s: %s" % (tb.tb_lineno, exc_obj)) - return {} + if len(parts) > 1 and parts[1] == plc_name: + dev_name = parts[-1] + if len(parts) > 3 and parts[-2] == clicked_name: + dev_name = clicked_name + "_" + parts[-1] + else: + dev_name = parts[-1] + prefix = clicked_name + "_" + + # === 🟢 NEW: Chute FIOM match === + if is_chute and dev_name.startswith(clicked_name + "_"): + global_device_mapping[dev_name] = { + "tagPath": tag_prop, + "zone": view_folder + } + continue + + # === Default inclusion === + if dev_name.startswith(prefix) or (len(parts) > 3 and parts[-2] == clicked_name): + global_device_mapping[dev_name] = { + "tagPath": tag_prop, + "zone": view_folder + } + + # === Special Case: JR Buttons === + elif "/JR/" in tag_prop.upper(): + try: + jr_parts = tag_prop.split("/JR/") + if len(jr_parts) > 1: + sub_path = jr_parts[1] + if sub_path.startswith(clicked_name + "_JR"): + dev_name = sub_path.split("/")[0] + global_device_mapping[dev_name] = { + "tagPath": tag_prop, + "zone": view_folder + } + except: + pass + + shared_jr_pe_map = { + "S03_CH101": ["S03_1_JR1", "S03_1_LRPE1"], + "S03_CH103": ["S03_1_JR1", "S03_1_LRPE1"], + "S03_CH105": ["S03_1_JR1", "S03_1_LRPE1"], + "S03_CH107": ["S03_1_JR3", "S03_1_LRPE3"], + "S03_CH108": ["S03_1_JR4", "S03_1_LRPE4"], + "S03_CH109": ["S03_1_JR3", "S03_1_LRPE3"], + "S03_CH110": ["S03_1_JR4", "S03_1_LRPE4"], + "S03_CH111": ["S03_1_JR3", "S03_1_LRPE3"], + "S03_CH112": ["S03_1_JR2", "S03_1_LRPE2"], + "S03_CH113": ["S03_1_JR5", "S03_1_LRPE5"], + "S03_CH114": ["S03_1_JR6", "S03_1_LRPE6"], + "S03_CH115": ["S03_1_JR5", "S03_1_LRPE5"], + "S03_CH116": ["S03_1_JR6", "S03_1_LRPE6"], + "S03_CH117": ["S03_1_JR5", "S03_1_LRPE5"], + "S03_CH118": ["S03_1_JR6", "S03_1_LRPE6"], + "S03_CH119": ["S03_1_JR7", "S03_1_LRPE7"], + "S03_CH120": ["S03_1_JR8", "S03_1_LRPE8"], + "S03_CH121": ["S03_1_JR7", "S03_1_LRPE7"], + "S03_CH122": ["S03_1_JR8", "S03_1_LRPE8"], + "S03_CH123": ["S03_1_JR7", "S03_1_LRPE7"], + "S03_CH124": ["S03_1_JR8", "S03_1_LRPE8"], + } + shared_fiom_map = { + "NCS1_1": ["S03_1_FIOM_5", "S03_1_FIOM_9", "S03_1_FIOM_1", "S03_1_FIOM_2","S03_1_FIOM_3","S03_1_FIOM_4", "S03_1_FIOM_6","S03_1_FIOM_7", "S03_1_FIOM_8"], + } + + if clicked_name in shared_jr_pe_map: + extra_devices = shared_jr_pe_map[clicked_name] + for dev in extra_devices: + try: + # Base tag (for PE) + base_tag = "System/MCM02/Station/Chute_JR/" + dev + # JR subtag (for JR button) + jr_tag = base_tag + "/JR" if dev.endswith("JR1") else base_tag + + for tag_candidate in [base_tag, jr_tag]: + global_device_mapping[dev] = { + "tagPath": tag_candidate, + "zone": "Chute_JR" + } + except Exception as ex: + system.perspective.print("Error adding JR/PE for {}: {}".format(clicked_name, ex)) + + if clicked_name in shared_fiom_map: + for dev in shared_fiom_map[clicked_name]: + tag_path = "System/{}/IO_Block/FIO/{}".format(plc_name, dev) + global_device_mapping[dev] = { + "tagPath": tag_path, + "zone": "FIO" + } + + return global_device_mapping + + except Exception as e: + whid = "unknown" + try: + whid = system.tag.readBlocking("Configuration/FC")[0].value + except: + pass + logger = system.util.getLogger("%s-build_device_mapping" % whid) + exc_type, exc_obj, tb = sys.exc_info() + logger.error("Error at line %s: %s" % (tb.tb_lineno, exc_obj)) + return {} + + + + +# ====================================================== +# Device Table Builder +# ====================================================== def build_device_table(self): - """ - Converts global_device_mapping into a list of dictionaries: - Keys: Device, Status - Reads each tag value, falls back to 'Unknown' if error/null. - """ - rows = [] - state_mappings = { - 0: "Closed", - 1: "Actuated", - 2: "Communication Faulted", - 3: "Conveyor Running In Maintenance Mode", - 4: "Disabled", - 5: "Disconnected", - 6: "Stopped", - 7: "Enabled Not Running", - 8: "Encoder Fault", - 9: "Energy Management", - 10: "ESTOP Was Actuated", - 11: "EStopped", - 12: "EStopped Locally", - 13: "Extended Faulted", - 14: "Full", - 15: "Gaylord Start Pressed", - 16: "Jam Fault", - 17: "Jammed", - 18: "Loading Allowed", - 19: "Loading Not Allowed", - 20: "Low Air Pressure Fault Was Present", - 21: "Maintenance Mode", - 22: "Conveyor Stopped In Maintenance Mode", - 23: "Motor Faulted", - 24: "Motor Was Faulted", - 25: "Normal", - 26: "Off Inactive", - 27: "Open", - 28: "PLC Ready To Run", - 29: "Package Release Pressed", - 30: "Power Branch Was Faulted", - 31: "Pressed", - 32: "Ready To Receive", - 33: "Running", - 34: "Started", - 35: "Stopped", - 36: "System Started", - 37: "Unknown", - 38: "VFD Fault", - 39: "Conveyor Running In Power Saving Mode", - 40: "Conveyor Jogging In Maintenance Mode", - 41: "VFD Reset Required", - 42: "Jam Reset Push Button Pressed", - 43: "Start Push Button Pressed", - 44: "Stop Push Button Pressed", - 45: "No Container", - 46: "Ready To Be Enabled", - 47: "Half Full", - 48: "Enabled", - 49: "Tipper Faulted" - } + rows = [] + try: + for dev_name, info in global_device_mapping.items(): + tagPath = info.get("tagPath", "") + if not tagPath: + continue - try: - for dev_name, info in global_device_mapping.items(): - tagPath = info.get("tagPath", "") - status_value = "" - provider = "[" + self.session.custom.fc + "_SCADA_TAG_PROVIDER]" - path = provider + tagPath + "/STATE" - - if tagPath: - try: - result = system.tag.readBlocking([path])[0] - status_value = state_mappings.get(result.value, "Unknown") - except: - status_value = "Unknown" + provider = "[" + self.session.custom.fc + "_SCADA_TAG_PROVIDER]" + rows.extend(read_device_status(tagPath, provider, dev_name)) - # Append as dictionary - rows.append({ - 'Device': dev_name, - 'Status': status_value - }) - - return rows - - except Exception as e: - system.perspective.print("Error building device table: %s" % e) - return [] # Return empty list on error + return rows + except Exception as e: + system.perspective.print("Error building device table: %s" % e) + return [] +# ====================================================== +# Get All Tags for Clicked Device +# ====================================================== def getAllTags(self, tagPath, section="all"): - """ - Reads all tags under a UDT instance (recursively) and returns a list of dictionaries. + """ + Reads all tags under a UDT instance (recursively) + and returns a list of dictionaries: + [ + {"Name": "State", "OPC Path": "System/MCM01/...", "Value": "Running"}, + ... + ] + """ + rows = [] - Supports: - - VFD (Drive folder) - - Conveyor (skips Drive) - - Chute (root + PE/PRX/EN tags) - - Single Photoeyes (PE1/PE2) - - Single Prox Sensors (PRX1/PRX2) - - Enable buttons (EN_Color, EN_State, EN_Priority) - - Tracking Photoeyes (TPE, handles both folder- and struct-style UDTs) - """ + try: + providerPath = "[" + self.session.custom.fc + "_SCADA_TAG_PROVIDER]" + driveFolderName = "Drive" - rows = [] + # === Utility: read a single atomic tag === + def readSingleTag(path, prefix=""): + try: + result = system.tag.readBlocking([providerPath + path])[0] + value = str(result.value) if result.quality.isGood() else "Unknown" + except: + value = "Unknown" - try: - providerPath = "[" + self.session.custom.fc + "_SCADA_TAG_PROVIDER]" - driveFolderName = "Drive" + displayName = prefix + path.split("/")[-1] if prefix else path.split("/")[-1] + rows.append({ + "Name": displayName, + "OPC Path": path, + "Value": value + }) + # === Utility: recursive browse === + def browseRecursive(basePath, prefix=""): + children = system.tag.browse(providerPath + basePath).getResults() + for child in children: + tagType = str(child.get("tagType", "")) + name = str(child.get("name", "")) + fullPath = str(child.get("fullPath", "")) - # === Utility: read a single atomic tag === - def readSingleTag(path, prefix=""): - try: - result = system.tag.readBlocking([providerPath + path])[0] - value = str(result.value) if result.quality.isGood() else "Unknown" - except: - value = "Unknown" + if fullPath.startswith("[") and "]" in fullPath: + fullPath = fullPath.split("]", 1)[1] - displayName = prefix + path.split("/")[-1] if prefix else path.split("/")[-1] - rows.append({ - "Name": displayName, - "OPC Path": path, - "Value": value - }) + # --- Conveyor filter (skip Drive folder) --- + if section == "conveyor" and name == driveFolderName: + continue - # === Utility: recursive browse === - def browseRecursive(basePath, prefix=""): - children = system.tag.browse(providerPath + basePath).getResults() + if tagType == "Folder": + # --- Skip JR subfolder if current device is LRPE --- + if name.upper() == "JR" and "_JR" in basePath.upper(): + continue + newPrefix = prefix + name + "/" if prefix else name + "/" + browseRecursive(basePath + "/" + name, newPrefix) + elif tagType == "AtomicTag": + readSingleTag(fullPath, prefix) - for child in children: - tagType = str(child.get("tagType", "")) - name = str(child.get("name", "")) - fullPath = str(child.get("fullPath", "")) + # === MAIN ENTRY POINT === - if fullPath.startswith("[") and "]" in fullPath: - fullPath = fullPath.split("]", 1)[1] + # --- Case 1: VFD --- + if section == "vfd": + drivePath = tagPath + "/" + driveFolderName + browseRecursive(drivePath) - # --- Conveyor filter (skip Drive folder) --- - if section == "conveyor" and name == driveFolderName: - continue + # --- Case 2: Flat EN_ tags (Chutes) --- + elif tagPath.upper().endswith("/EN"): + parentPath = "/".join(tagPath.split("/")[:-1]) + children = system.tag.browse(providerPath + parentPath).getResults() + for child in children: + tagType = str(child.get("tagType", "")) + name = str(child.get("name", "")) + if tagType == "AtomicTag" and name.upper().startswith("EN_"): + fullPath = str(child.get("fullPath", "")) + if fullPath.startswith("[") and "]" in fullPath: + fullPath = fullPath.split("]", 1)[1] + readSingleTag(fullPath) - if tagType == "Folder": - newPrefix = prefix + name + "/" if prefix else name + "/" - browseRecursive(basePath + "/" + name, newPrefix) - elif tagType == "AtomicTag": - readSingleTag(fullPath, prefix) + # --- Case 3: Single Sensors (PE/PRX) --- + elif tagPath.upper().endswith(("PE1", "PE2", "PRX1", "PRX2")) and "/TPE/" not in tagPath.upper(): + readSingleTag(tagPath) - # === MAIN ENTRY POINT === - if section == "vfd": - # Browse only inside Drive folder - drivePath = tagPath + "/" + driveFolderName - browseRecursive(drivePath) + # --- Case 4: Default / Fallback --- + else: + browseResult = system.tag.browse(providerPath + tagPath).getResults() - elif tagPath.upper().endswith("/EN"): - # --- Handle flat EN_ tags --- - parentPath = "/".join(tagPath.split("/")[:-1]) - children = system.tag.browse(providerPath + parentPath).getResults() + if not browseResult: + # Possibly a struct-style UDT (like some TPEs) + system.perspective.print("Empty browse for {}, checking struct value...".format(tagPath)) + try: + result = system.tag.readBlocking([providerPath + tagPath])[0] + value = result.value - for child in children: - tagType = str(child.get("tagType", "")) - name = str(child.get("name", "")) - if tagType == "AtomicTag" and name.upper().startswith("EN_"): - fullPath = str(child.get("fullPath", "")) - if fullPath.startswith("[") and "]" in fullPath: - fullPath = fullPath.split("]", 1)[1] - readSingleTag(fullPath) + # === Expand STRUCT === + if isinstance(value, dict): + system.perspective.print("Detected STRUCT value, expanding {}".format(tagPath)) - elif tagPath.upper().endswith(("PE1", "PE2", "PRX1", "PRX2")) and "/TPE/" not in tagPath.upper(): - # --- Single sensors --- - readSingleTag(tagPath) + def flattenStruct(struct, base=""): + for k, v in struct.items(): + newName = base + "/" + k if base else k + if isinstance(v, dict): + flattenStruct(v, newName) + else: + rows.append({ + "Name": newName, + "OPC Path": tagPath + "/" + newName, + "Value": str(v) + }) - else: - # --- Default path --- - browseResult = system.tag.browse(providerPath + tagPath).getResults() + flattenStruct(value) - if not browseResult: - # Possibly a struct-style UDT (like some TPEs) - system.perspective.print("Empty browse for {}, checking struct value...".format(tagPath)) - try: - result = system.tag.readBlocking([providerPath + tagPath])[0] - value = result.value + else: + # Not a struct, read normally + readSingleTag(tagPath) - # If we got a STRUCT, expand it into sub-rows - if isinstance(value, dict): - system.perspective.print("Detected STRUCT value, expanding {}".format(tagPath)) + except Exception as ex: + system.perspective.print("Fallback read failed for {}: {}".format(tagPath, ex)) - def flattenStruct(struct, base=""): - for k, v in struct.items(): - newName = base + "/" + k if base else k - if isinstance(v, dict): - flattenStruct(v, newName) - else: - rows.append({ - "Name": newName, - "OPC Path": tagPath + "/" + newName, - "Value": str(v) - }) + else: + # Normal browse case + browseRecursive(tagPath) - flattenStruct(value) - else: - # Not a struct, just read it normally - readSingleTag(tagPath) - except Exception as ex: - system.perspective.print("Fallback read failed for {}: {}".format(tagPath, ex)) - else: - # Normal case — browse folder/UDT structure - browseRecursive(tagPath) + return rows - return rows - - except Exception as e: - system.perspective.print("Error in getAllTags: {}".format(e)) - return [] + except Exception as e: + system.perspective.print("Error in getAllTags: {}".format(e)) + return [] diff --git a/BNA8_autStand/ignition/script-python/autStand/devices/resource.json b/BNA8_autStand/ignition/script-python/autStand/devices/resource.json index da953364..720820ba 100644 --- a/BNA8_autStand/ignition/script-python/autStand/devices/resource.json +++ b/BNA8_autStand/ignition/script-python/autStand/devices/resource.json @@ -9,9 +9,9 @@ "attributes": { "lastModification": { "actor": "admin", - "timestamp": "2025-11-05T10:10:15Z" + "timestamp": "2025-11-06T09:07:05Z" }, "hintScope": 2, - "lastModificationSignature": "509aec4ea42ad044944f9f2f53d5e610bd5fdb0ed852c6d392f7a94816fa6cd9" + "lastModificationSignature": "1aab25cf2caca967d0c6fc4a2cbc161a07f54ef8faf7c2675b94d53bb2e289b9" } } \ No newline at end of file