Getting this error when trying to view alarms

Hi everyone,
Im a beginner with designer and im trying to view the past alarms. Whenever i press the refresh button which is needed to view the alarms. I get this error. when i see if I'm not sure where to start.
any help would be very much appreciated

Best wishes



Looks like some script was converted from v7.9 and the script library names changed.

Show us the script (use the preformatted text option in this forum) so we can see the lines mentioned in that backtrace.

I'm defiantly being dumb and blind, where can i find this script?

The button you clicked has an actionPerformed event script, as noted in the error. In the designer, right click on the button and pick scripting from that context menu. (Or select the button and press Ctrl-J.)

Really Sorry for the late reply, So I went to the button, pressed control J and opened the script editor. From this it seems that there is only 2 lines of script? not 208 :joy:

Best wishes

So I might have found the line 208. However, I had to press the timer icon to find it. Not sure why though?.


def doLotsOfStuff():
    if event.source.parent.update:
        tags = ["Configuration/FC"]
        values = system.tag.readBlocking(tags)
        oWHID = values[0].value

        oStartDT = event.source.parent.getComponent("StartDate").text
        oStopDT = event.source.parent.getComponent("EndDate").text
        iso8601_dates = shared.EURME_SCADA.SAP.sap_scripts.convert_to_iso8601(oStartDT, oStopDT)
        udt = event.source.parent.tagPath

        start_date = datetime.strptime(iso8601_dates[0], "%Y-%m-%dT%H:%M:%S.%fZ")
        end_date = datetime.strptime(iso8601_dates[1], "%Y-%m-%dT%H:%M:%S.%fZ")
        interval_minutes = 720
        intervals = shared.EURME_SCADA.SAP.sap_scripts.generate_time_intervals(start_date, end_date, interval_minutes)
        max_concurrent_threads = len(intervals)
        args = [(interval[0], interval[1], oWHID, udt) for interval in intervals]

        start_time = time.time()

        executor = Executors.newFixedThreadPool(max_concurrent_threads)
        futures = [executor.submit(APICallable(arg)) for arg in args]
        results = [future.get() for future in futures]

        executor.shutdown()

        end_time = time.time()

        api_response = {"data": []}
        for result in results:
            if isinstance(result, list):
                api_response["data"].extend(result)
            else:
                print("Unexpected response format: {}".format(result))

        print("Time taken for all API requests: {:.2f} seconds".format(end_time - start_time))
        print("Number of items in combined 'data': {}".format(len(api_response["data"])))

        data_sap = []
        if not "No data found" in api_response["data"]:
            seconds_to_hours_conv = {item["duration_millis"]: shared.EURME_SCADA.SAP.sap_scripts.seconds_to_hours(item["duration_millis"] / 1000) for item in api_response["data"]}
            for item in api_response["data"]:
                timestampUTC = item["time_start"]
                timestamp = shared.EURME_SCADA.SAP.sap_scripts.convert_to_local_time_with_fractional_seconds(timestampUTC)
                dt = datetime.strptime(timestamp, "%Y-%m-%d %H:%M:%S.%f")
                date_without_milliseconds = dt.strftime("%Y-%m-%d %H:%M:%S")
                duration = seconds_to_hours_conv[item["duration_millis"]]

                data_sap.append([date_without_milliseconds, duration, item["name"], item["priority"], item["udt_tag"], item["displaypath"]])
        else:
            system.gui.warningBox("No data found.")
            event.source.parent.computationInProgress = False

        headers_sap = ["TimeStamp", "Duration", "Name", "Priority", "UDT_tag", "DisplayPath"]

        def parse_timestamp(ts):
            dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
            return dateFormat.parse(ts)

        data_sap.sort(
            key=lambda x: (
                -x[3],  # Sort by column 3 in descending order
                -parse_timestamp(x[0]).getTime(),  # Sort by column 0 (timestamp) in descending order, getting time in milliseconds
            )
        )
        historical_data = system.dataset.toDataSet(headers_sap, data_sap)
        event.source.parent.getComponent("table_ts").data = historical_data

        system.util.invokeLater(update_ui)


if not event.source.parent.computationInProgress:
    event.source.parent.computationInProgress = True
    event.source.parent.runTimerForScripting = False
    system.util.invokeAsynchronous(doLotsOfStuff)

The is one exceedingly dangerous background script. It is freely accessing components and their properties from a background thread. This can and eventually will completely lock up your designer or your Vision client.

It must be completely rewritten to not do that. See this topic for techniques to follow when using asynchronous tasks:

(It is an old post, but still applies to Vision.)

Read the whole thing.

2 Likes

Hi everyone,
I'm a beginner with this so any help would make me happy lol. I imported this project and im trying to view the alarms. However, Every time, I go to press the button. I get this error.
I checked if the key data exists in the dictionary and it doesn't. not sure what to do now.

Any help would be much appreciated.

Here is the error code:

Traceback (most recent call last):
  File "<event:actionPerformed>", line 222, in doLotsOfStuff
  File "<event:actionPerformed>", line 49, in call
  File "<event:actionPerformed>", line 18, in filter_by_udt_tag
KeyError: 'data'

	at java.base/java.util.concurrent.FutureTask.report(Unknown Source)
	at java.base/java.util.concurrent.FutureTask.get(Unknown Source)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.base/java.lang.reflect.Method.invoke(Unknown Source)
java.util.concurrent.ExecutionException: java.util.concurrent.ExecutionException: Traceback (most recent call last):
  File "<event:actionPerformed>", line 49, in call
  File "<event:actionPerformed>", line 18, in filter_by_udt_tag
KeyError: 'data'


	at org.python.core.Py.JavaError(Py.java:547)
	at org.python.core.Py.JavaError(Py.java:538)
	at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:192)
	at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:208)
	at org.python.core.PyObject.__call__(PyObject.java:461)
	at org.python.core.PyObject.__call__(PyObject.java:465)
	at org.python.core.PyMethod.__call__(PyMethod.java:126)
	at org.python.pycode._pyx109.doLotsOfStuff$8(<event:actionPerformed>:268)
	at org.python.pycode._pyx109.call_function(<event:actionPerformed>)
	at org.python.core.PyTableCode.call(PyTableCode.java:173)
	at org.python.core.PyBaseCode.call(PyBaseCode.java:306)
	at org.python.core.PyFunction.function___call__(PyFunction.java:474)
	at org.python.core.PyFunction.__call__(PyFunction.java:469)
	at org.python.core.PyFunction.__call__(PyFunction.java:464)
	at com.inductiveautomation.ignition.common.script.ScriptManager.runFunction(ScriptManager.java:846)
	at com.inductiveautomation.ignition.client.script.DesignerSystemUtilities.lambda$_invokeAsyncImpl$1(DesignerSystemUtilities.java:140)
	at java.base/java.lang.Thread.run(Unknown Source)
Caused by: java.util.concurrent.ExecutionException: Traceback (most recent call last):
  File "<event:actionPerformed>", line 49, in call
  File "<event:actionPerformed>", line 18, in filter_by_udt_tag
KeyError: 'data'

	at java.base/java.util.concurrent.FutureTask.report(Unknown Source)
	at java.base/java.util.concurrent.FutureTask.get(Unknown Source)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.base/java.lang.reflect.Method.invoke(Unknown Source)
	at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:190)
	... 14 more
Caused by: Traceback (most recent call last):
  File "<event:actionPerformed>", line 49, in call
  File "<event:actionPerformed>", line 18, in filter_by_udt_tag
KeyError: 'data'

	at org.python.core.Py.KeyError(Py.java:226)
	at org.python.core.PyObject.__getitem__(PyObject.java:719)
	at org.python.pycode._pyx109.filter_by_udt_tag$1(<event:actionPerformed>:19)
	at org.python.pycode._pyx109.call_function(<event:actionPerformed>)
	at org.python.core.PyTableCode.call(PyTableCode.java:173)
	at org.python.core.PyBaseCode.call(PyBaseCode.java:150)
	at org.python.core.PyFunction.__call__(PyFunction.java:426)
	at org.python.pycode._pyx109.call$4(<event:actionPerformed>:50)
	at org.python.pycode._pyx109.call_function(<event:actionPerformed>)
	at org.python.core.PyTableCode.call(PyTableCode.java:173)
	at org.python.core.PyBaseCode.call(PyBaseCode.java:306)
	at org.python.core.PyBaseCode.call(PyBaseCode.java:197)
	at org.python.core.PyFunction.__call__(PyFunction.java:485)
	at org.python.core.PyMethod.instancemethod___call__(PyMethod.java:237)
	at org.python.core.PyMethod.__call__(PyMethod.java:228)
	at org.python.core.PyMethod.__call__(PyMethod.java:218)
	at org.python.core.PyMethod.__call__(PyMethod.java:213)
	at org.python.core.PyObject._jcallexc(PyObject.java:3565)
	at org.python.proxies.__builtin__$APICallable$18.call(Unknown Source)
	at java.base/java.util.concurrent.FutureTask.run(Unknown Source)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	... 1 more

Ignition v8.1.31 (b2023081007)
Java: Azul Systems, Inc. 11.0.18

and here is the script:

import time
import sys
from urllib2 import urlopen
from datetime import datetime
from java.util.concurrent import Executors, Callable
from java.text import SimpleDateFormat


def filter_by_udt_tag(data, udt_tag):
    """
    Filters the data objects based on the UDT_TAG key.
    Parameters:
    data (dict): A dictionary containing a list of data objects.
    udt_tag (str): The UDT_TAG value to filter by.
    Returns:
    list: A list of filtered data objects.
    """
    filtered_data = [item for item in data["data"] if item.get("udt_tag") == udt_tag]
    return filtered_data


class APICallable(Callable):
    """
    A class that represents an API callable object.
    This class encapsulates the arguments required for an API call and provides a method to execute the call.
    Attributes:
        args (dict): The arguments required for the API call.
    Methods:
        call():
            Sends an API request with the stored arguments.
            Returns the response from the API request.
    """

    def __init__(self, args):
        """
        Initializes the APICallable object with the given arguments.
        Args:
            args (dict): A dictionary of arguments required for the API call.
        """
        self.args = args

    def call(self):
        """
        Sends an API request using the stored arguments.
        Returns:
            Response: The response from the API request.
        """
        response = send_api_request(self.args)
        filtered_response = filter_by_udt_tag(response, self.args[3])
        return filtered_response


def send_api_request(args):
    """
    Sends an API request with the given arguments.
    This function extracts the start date, end date, and whid from the arguments,
    formats the dates into ISO 8601 format, and makes a common API request.
    Args:
        args (tuple): A tuple containing the start date (str), end date (str), and whid (str).
    Returns:
        Response: The response from the API request.
        If an exception occurs, returns a dictionary with the error message.
    """
    start_date, end_date, whid, udt = args
    try:
        iso8601_dates = [start_date, end_date]
        response = make_api_request_common(iso8601_dates, None, whid, udt)
        return response
    except Exception as e:
        return {"error": str(e)}


def update_ui():
    """
    Update the user interface with specific flags and messages.
    """
    event.source.parent.computationInProgress = False
    event.source.parent.update = False


def make_api_request_common(iso8601_dates, params=None, whid=None, udt=None):
    """
    Make a common API request for historical alarms based on the specified timestamp range and parameters.
    Args:
    - iso8601_dates (list): A list containing the start and end timestamps in ISO8601 format.
    - params (str, optional): A string representing the next token for paginated requests (default is None).
    - whid (str, optional): A string representing the warehouse ID (default is None).
    Returns:
    dict: A dictionary containing the API response for historical alarms.
    Note:
    This function handles paginated requests and extends the response data if a 'next_token' is present.
    """

    mapRegion = Global.iStream.gatewayRegion.get("FE")

    if mapRegion == "AU" or mapRegion == "AU-NAWS":
        default_region = "ap-southeast-2"
        default_aws_service = "execute-api"
        default_host = "https://sap-service-au.sap.rme.amazon.dev/"
    else:
        default_region = "eu-west-1"
        default_aws_service = "execute-api"
        default_host = "https://sap-service-eu.sap.rme.amazon.dev/"

    # Get AWS credentials
    access_key, secret_key = shared.EURME_SCADA.SAP.sap_scripts.retrieve_ssm()

    json_data = {
        "whid": whid,
        "engine": "SCADA",
        "t_start": iso8601_dates[0],
        "t_end": iso8601_dates[1],
        "udt_tag": udt,
    }

    if params is not None:
        json_data["next_token"] = params

    api_request = Global.iStream.aws4auth.IamRequest(
        url=default_host,
        path="data/historicalAlarms",
        json=json_data,
        access_key=access_key,
        secret_key=secret_key,
        aws_region=default_region,
        aws_service=default_aws_service,
    )

    api_response = system.util.jsonDecode(str(urlopen(api_request).readlines()[0]))

    if "next_token" in api_response:
        params = api_response["next_token"]
        udt = event.source.parent.tagPath
        new_api_response = make_api_request_common(iso8601_dates, params, whid, udt)
        api_response["data"].extend(new_api_response["data"])

    return api_response


if event.source.parent.fillColors:
    try:
        tagColorConfig = event.source.parent.colorsConfig
        for row in range(tagColorConfig.getRowCount()):
            JSONString = {}
            for col in range(tagColorConfig.getColumnCount()):
                if not tagColorConfig.getColumnName(col) == "condition":
                    JSONString[str(tagColorConfig.getColumnName(col))] = str(tagColorConfig.getValueAt(row, col))

            alarmDescription = tagColorConfig.getValueAt(row, 0)

            if "Diagnostic" in alarmDescription:
                event.source.parent.Diagnostic = JSONString
            if "ActiveUnacked" in alarmDescription:
                if "{priority}=1" in alarmDescription:
                    event.source.parent.ActiveUnackedSev1 = JSONString
                if "{priority}=2" in alarmDescription:
                    event.source.parent.ActiveUnackedSev2 = JSONString
                if "{priority}=3" in alarmDescription:
                    event.source.parent.ActiveUnackedSev3 = JSONString
                if "{priority}=4" in alarmDescription:
                    event.source.parent.ActiveUnackedSev4 = JSONString

            if "ClearUnacked" in alarmDescription:
                if "{priority}=1" in alarmDescription:
                    event.source.parent.ClearUnackedSev1 = JSONString
                if "{priority}=2" in alarmDescription:
                    event.source.parent.ClearUnackedSev2 = JSONString
                if "{priority}=3" in alarmDescription:
                    event.source.parent.ClearUnackedSev3 = JSONString
                if "{priority}=4" in alarmDescription:
                    event.source.parent.ClearUnackedSev4 = JSONString
            if "ActiveAcked" in alarmDescription:
                if "{priority}=1" in alarmDescription:
                    event.source.parent.ActiveAckedSev1 = JSONString
                if "{priority}=2" in alarmDescription:
                    event.source.parent.ActiveAckedSev2 = JSONString
                if "{priority}=3" in alarmDescription:
                    event.source.parent.ActiveAckedSev3 = JSONString
                if "{priority}=4" in alarmDescription:
                    event.source.parent.ActiveAckedSev4 = JSONString
            if "ClearAcked" in alarmDescription:
                event.source.parent.ClearAckedSev4 = JSONString
                if "{priority}=1" in alarmDescription:
                    event.source.parent.ClearAckedSev1 = JSONString
                if "{priority}=2" in alarmDescription:
                    event.source.parent.ClearAckedSev2 = JSONString
                if "{priority}=3" in alarmDescription:
                    event.source.parent.ClearAckedSev3 = JSONString
                if "{priority}=4" in alarmDescription:
                    event.source.parent.ClearAckedSev4 = JSONString

    except BaseException:
        event.source.parent.loadData = False
        exc_type, exc_obj, tb = sys.exc_info()
        lineno = tb.tb_lineno
        error_description = str(lineno) + " , " + str(exc_type) + " , " + str(exc_obj)
        system.gui.messageBox(error_description)


def doLotsOfStuff():
    if event.source.parent.update:
        tags = ["Configuration/FC"]
        values = system.tag.readBlocking(tags)
        oWHID = values[0].value

        oStartDT = event.source.parent.getComponent("StartDate").text
        oStopDT = event.source.parent.getComponent("EndDate").text
        iso8601_dates = shared.EURME_SCADA.SAP.sap_scripts.convert_to_iso8601(oStartDT, oStopDT)
        udt = event.source.parent.tagPath

        start_date = datetime.strptime(iso8601_dates[0], "%Y-%m-%dT%H:%M:%S.%fZ")
        end_date = datetime.strptime(iso8601_dates[1], "%Y-%m-%dT%H:%M:%S.%fZ")
        interval_minutes = 720
        intervals = shared.EURME_SCADA.SAP.sap_scripts.generate_time_intervals(start_date, end_date, interval_minutes)
        max_concurrent_threads = len(intervals)
        args = [(interval[0], interval[1], oWHID, udt) for interval in intervals]

        start_time = time.time()

        executor = Executors.newFixedThreadPool(max_concurrent_threads)
        futures = [executor.submit(APICallable(arg)) for arg in args]
        results = [future.get() for future in futures]

        executor.shutdown()

        end_time = time.time()

        api_response = {"data": []}
        for result in results:
            if isinstance(result, list):
                api_response["data"].extend(result)
            else:
                print("Unexpected response format: {}".format(result))

        print("Time taken for all API requests: {:.2f} seconds".format(end_time - start_time))
        print("Number of items in combined 'data': {}".format(len(api_response["data"])))

        data_sap = []
        if not "No data found" in api_response["data"]:
            seconds_to_hours_conv = {item["duration_millis"]: shared.EURME_SCADA.SAP.sap_scripts.seconds_to_hours(item["duration_millis"] / 1000) for item in api_response["data"]}
            for item in api_response["data"]:
                timestampUTC = item["time_start"]
                timestamp = shared.EURME_SCADA.SAP.sap_scripts.convert_to_local_time_with_fractional_seconds(timestampUTC)
                dt = datetime.strptime(timestamp, "%Y-%m-%d %H:%M:%S.%f")
                date_without_milliseconds = dt.strftime("%Y-%m-%d %H:%M:%S")
                duration = seconds_to_hours_conv[item["duration_millis"]]

                data_sap.append([date_without_milliseconds, duration, item["name"], item["priority"], item["udt_tag"], item["displaypath"]])
        else:
            system.gui.warningBox("No data found.")
            event.source.parent.computationInProgress = False

        headers_sap = ["TimeStamp", "Duration", "Name", "Priority", "UDT_tag", "DisplayPath"]

        def parse_timestamp(ts):
            dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
            return dateFormat.parse(ts)

        data_sap.sort(
            key=lambda x: (
                -x[3],  # Sort by column 3 in descending order
                -parse_timestamp(x[0]).getTime(),  # Sort by column 0 (timestamp) in descending order, getting time in milliseconds
            )
        )
        historical_data = system.dataset.toDataSet(headers_sap, data_sap)
        event.source.parent.getComponent("table_ts").data = historical_data

        system.util.invokeLater(update_ui)


if not event.source.parent.computationInProgress:
    event.source.parent.computationInProgress = True
    event.source.parent.runTimerForScripting = False
    system.util.invokeAsynchronous(doLotsOfStuff)

Here is a screenshot of me see if the key data is present

Best wishes

I moved this post back into this topic. Duplicate posts are against this forum's rules. Please read the "Keep it tidy" section, @farhad_Hossain .

thanks for that. :slightly_smiling_face:
For the original issue with the global name shared, it was not in my global scripting. I think that what its called. So i imported the scripting from the original project and now I didn't get that error. However, something new pops up which mentions about a data key.

Your script console example shows you creating a dictionary with just an "error" key, then looking up a "data" key. So of course it doesn't have it.

As for your original code not have a "data" key in the given dictionary, there's no way to tell why. You will have to study all of the relevant code, and probably add logging of variables to see what is going on. Which you probably need to do anyways when you rewrite the asynchronous function.

Erm, could you just use the alarm status table or alarm journal component to show alarms?

1 Like

I'm not sure ill give it a try.

Some background. This is an imported project, so the original one works fine, and im just doing it for testing small new changes.