diff --git a/MTN6_SCADA/com.inductiveautomation.perspective/views/Windows/Statistics/view.json b/MTN6_SCADA/com.inductiveautomation.perspective/views/Windows/Statistics/view.json index dbcd735..849d607 100644 --- a/MTN6_SCADA/com.inductiveautomation.perspective/views/Windows/Statistics/view.json +++ b/MTN6_SCADA/com.inductiveautomation.perspective/views/Windows/Statistics/view.json @@ -55,7 +55,7 @@ }, "onChange": { "enabled": null, - "script": "\n # \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n # 1. Database Connection Check\n # \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n try:\n # Check if MariaDB exists and is ready\n connections \u003d system.db.getConnections()\n maria_conn \u003d next((c for c in connections if c.name \u003d\u003d \"MariaDB\"), None)\n \n if not maria_conn:\n print(\"❌ MariaDB connection not configured in Ignition\")\n self.props.data \u003d system.dataset.toDataSet([\"Error\"], [[\"Database connection \u0027MariaDB\u0027 not found\"]])\n return\n \n if maria_conn.status \u003d\u003d \"Disabled\":\n print(\"⚠️ MariaDB is disabled - attempting to enable...\")\n system.db.enableConnection(\"MariaDB\")\n system.util.sleep(2000) # Wait for connection attempt\n \n if maria_conn.status !\u003d \"Connected\":\n error_msg \u003d \"MariaDB status: {maria_conn.status}\"\n print(\"{error_msg}\")\n self.props.data \u003d system.dataset.toDataSet([\"Error\"], [[error_msg]])\n return\n \n # Quick ping test (3 second timeout)\n if not system.db.ping(\"MariaDB\", 3000):\n raise Exception(\"Database not responding to ping\")\n \n except Exception as e:\n error_msg \u003d \"Database connection failed: {str(e)}\"\n print(\"{error_msg}\")\n self.props.data \u003d system.dataset.toDataSet([\"Error\"], [[error_msg]])\n return\n\n # \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n # 2. Original Logic (Protected)\n # \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n try:\n path \u003d \"\"\n headers \u003d []\n graph \u003d []\n \n # Mode selection (unchanged)\n if self.parent.parent.parent.getChild(\"Aggregation_Mode\").getChild(\"Dropdown_Aggregation_mode\").props.value \u003d\u003d \"Count\":\n path \u003d \"Statistics/Hourly Scanner Count\"\n headers \u003d [\"Start Timestamp\",\"Hour\",\"Total (#)\",\"Good Read (#)\",\"No Read (#)\",\"Multi Read (#)\",\"No Code (#)\"]\n self.getSibling(\"Hourly Scanner\").props.series[0].tooltip.text \u003d \"Good Read (#): [bold]{valueY}[/]\"\n self.getSibling(\"Hourly Scanner\").props.series[1].tooltip.text \u003d \"No Read (#): [bold]{valueY}[/]\"\n self.getSibling(\"Hourly Scanner\").props.series[2].tooltip.text \u003d \"Multi Read (#): [bold]{valueY}[/]\"\n self.getSibling(\"Hourly Scanner\").props.series[3].tooltip.text \u003d \"No Code (#): [bold]{valueY}[/]\"\n self.getSibling(\"Hourly Scanner\").props.yAxes[0].value.range.max \u003d \"\"\n elif self.parent.parent.parent.getChild(\"Aggregation_Mode\").getChild(\"Dropdown_Aggregation_mode\").props.value \u003d\u003d \"Percentage\":\n path \u003d \"Statistics/Hourly Scanner Percent\"\n headers \u003d [\"Start Timestamp\",\"Hour\",\"Total (%)\",\"Good Read (%)\",\"No Read (%)\",\"Multi Read (%)\",\"No Code (%)\"]\n self.getSibling(\"Hourly Scanner\").props.series[0].tooltip.text \u003d \"Good Read (%): [bold]{valueY}[/]%\"\n self.getSibling(\"Hourly Scanner\").props.series[1].tooltip.text \u003d \"No Read (%): [bold]{valueY}[/]%\"\n self.getSibling(\"Hourly Scanner\").props.series[2].tooltip.text \u003d \"Multi Read (%): [bold]{valueY}[/]%\"\n self.getSibling(\"Hourly Scanner\").props.series[3].tooltip.text \u003d \"No Code (%): [bold]{valueY}[/]%\"\n self.getSibling(\"Hourly Scanner\").props.yAxes[0].value.range.max \u003d 100\n else:\n path \u003d \"Statistics/Hourly Scanner Rate\"\n headers \u003d [\"Start Timestamp\",\"Hour\",\"Total (pph)\",\"Good Read (pph)\",\"No Read (pph)\",\"Multi Read (pph)\",\"No Code (pph)\"]\n self.getSibling(\"Hourly Scanner\").props.series[0].tooltip.text \u003d \"Good Read (pph): [bold]{valueY}[/] pph\"\n self.getSibling(\"Hourly Scanner\").props.series[1].tooltip.text \u003d \"No Read (pph): [bold]{valueY}[/]\"\n self.getSibling(\"Hourly Scanner\").props.series[2].tooltip.text \u003d \"Multi Read (pph): [bold]{valueY}[/] pph\"\n self.getSibling(\"Hourly Scanner\").props.series[3].tooltip.text \u003d \"No Code (pph): [bold]{valueY}[/] pph\"\n self.getSibling(\"Hourly Scanner\").props.yAxes[0].value.range.max \u003d \"\"\n \n params \u003d {\n \"starttime\": self.parent.parent.parent.getChild(\"Period_not_Global_0\").custom.StartDate,\n \"endtime\": self.parent.parent.parent.getChild(\"Period_not_Global_0\").custom.EndDate\n }\n \n # Execute query with error handling\n data \u003d system.dataset.toPyDataSet(system.db.runNamedQuery(path, params))\n \n # Process data (unchanged)\n graph \u003d []\n for row in data: \n dict \u003d {\n \u0027Hour\u0027: row[\u0027Hour\u0027],\n \u0027GoodRead\u0027: row[\u0027GoodRead\u0027],\n \u0027NoRead\u0027: row[\u0027NoRead\u0027],\n \u0027MultiRead\u0027: row[\u0027MultiRead\u0027],\n \u0027NoCode\u0027: row[\u0027NoCode\u0027]\n }\n graph.append(dict)\n \n # Update components\n self.getSibling(\"Hourly Scanner\").props.dataSources.example \u003d graph\n self.props.data \u003d system.dataset.toDataSet(headers, data)\n \n except Exception as e:\n error_msg \u003d \"Query failed: {str(e)}\"\n print(\"🚨 {error_msg}\")\n self.props.data \u003d system.dataset.toDataSet([\"Error\"], [[error_msg]])" + "script": " db_tag_path \u003d \"[System]Gateway/Database/MariaDB/Available\"\n\t\n if(system.tag.readBlocking([db_tag_path])[0].value):\n path \u003d \"\"\n headers \u003d []\n graph \u003d []\n \n # Mode selection (unchanged)\n if self.parent.parent.parent.getChild(\"Aggregation_Mode\").getChild(\"Dropdown_Aggregation_mode\").props.value \u003d\u003d \"Count\":\n path \u003d \"Statistics/Hourly Scanner Count\"\n headers \u003d [\"Start Timestamp\",\"Hour\",\"Total (#)\",\"Good Read (#)\",\"No Read (#)\",\"Multi Read (#)\",\"No Code (#)\"]\n self.getSibling(\"Hourly Scanner\").props.series[0].tooltip.text \u003d \"Good Read (#): [bold]{valueY}[/]\"\n self.getSibling(\"Hourly Scanner\").props.series[1].tooltip.text \u003d \"No Read (#): [bold]{valueY}[/]\"\n self.getSibling(\"Hourly Scanner\").props.series[2].tooltip.text \u003d \"Multi Read (#): [bold]{valueY}[/]\"\n self.getSibling(\"Hourly Scanner\").props.series[3].tooltip.text \u003d \"No Code (#): [bold]{valueY}[/]\"\n self.getSibling(\"Hourly Scanner\").props.yAxes[0].value.range.max \u003d \"\"\n elif self.parent.parent.parent.getChild(\"Aggregation_Mode\").getChild(\"Dropdown_Aggregation_mode\").props.value \u003d\u003d \"Percentage\":\n path \u003d \"Statistics/Hourly Scanner Percent\"\n headers \u003d [\"Start Timestamp\",\"Hour\",\"Total (%)\",\"Good Read (%)\",\"No Read (%)\",\"Multi Read (%)\",\"No Code (%)\"]\n self.getSibling(\"Hourly Scanner\").props.series[0].tooltip.text \u003d \"Good Read (%): [bold]{valueY}[/]%\"\n self.getSibling(\"Hourly Scanner\").props.series[1].tooltip.text \u003d \"No Read (%): [bold]{valueY}[/]%\"\n self.getSibling(\"Hourly Scanner\").props.series[2].tooltip.text \u003d \"Multi Read (%): [bold]{valueY}[/]%\"\n self.getSibling(\"Hourly Scanner\").props.series[3].tooltip.text \u003d \"No Code (%): [bold]{valueY}[/]%\"\n self.getSibling(\"Hourly Scanner\").props.yAxes[0].value.range.max \u003d 100\n else:\n path \u003d \"Statistics/Hourly Scanner Rate\"\n headers \u003d [\"Start Timestamp\",\"Hour\",\"Total (pph)\",\"Good Read (pph)\",\"No Read (pph)\",\"Multi Read (pph)\",\"No Code (pph)\"]\n self.getSibling(\"Hourly Scanner\").props.series[0].tooltip.text \u003d \"Good Read (pph): [bold]{valueY}[/] pph\"\n self.getSibling(\"Hourly Scanner\").props.series[1].tooltip.text \u003d \"No Read (pph): [bold]{valueY}[/]\"\n self.getSibling(\"Hourly Scanner\").props.series[2].tooltip.text \u003d \"Multi Read (pph): [bold]{valueY}[/] pph\"\n self.getSibling(\"Hourly Scanner\").props.series[3].tooltip.text \u003d \"No Code (pph): [bold]{valueY}[/] pph\"\n self.getSibling(\"Hourly Scanner\").props.yAxes[0].value.range.max \u003d \"\"\n \n params \u003d {\n \"starttime\": self.parent.parent.parent.getChild(\"Period_not_Global_0\").custom.StartDate,\n \"endtime\": self.parent.parent.parent.getChild(\"Period_not_Global_0\").custom.EndDate\n }\n \n # Execute query with error handling\n data \u003d system.dataset.toPyDataSet(system.db.runNamedQuery(path, params))\n \n # Process data (unchanged)\n graph \u003d []\n for row in data: \n dict \u003d {\n \u0027Hour\u0027: row[\u0027Hour\u0027],\n \u0027GoodRead\u0027: row[\u0027GoodRead\u0027],\n \u0027NoRead\u0027: row[\u0027NoRead\u0027],\n \u0027MultiRead\u0027: row[\u0027MultiRead\u0027],\n \u0027NoCode\u0027: row[\u0027NoCode\u0027]\n }\n graph.append(dict)\n \n # Update components\n self.getSibling(\"Hourly Scanner\").props.dataSources.example \u003d graph\n self.props.data \u003d system.dataset.toDataSet(headers, data)\n " } }, "custom.time": { @@ -618,14 +618,42 @@ "$": [ "ds", 192, - 1747403903257 + 1747664567746 ], "$columns": [ { - "data": [ - "Database connection failed: {str(e)}" - ], - "name": "Error", + "data": [], + "name": "Start Timestamp", + "type": "String" + }, + { + "data": [], + "name": "Hour", + "type": "String" + }, + { + "data": [], + "name": "Total (#)", + "type": "String" + }, + { + "data": [], + "name": "Good Read (#)", + "type": "String" + }, + { + "data": [], + "name": "No Read (#)", + "type": "String" + }, + { + "data": [], + "name": "Multi Read (#)", + "type": "String" + }, + { + "data": [], + "name": "No Code (#)", "type": "String" } ] @@ -1911,7 +1939,7 @@ }, "onChange": { "enabled": null, - "script": "\t# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n\t# 1. Database Connection Check\n\t# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n\ttry:\n\t # Check if MariaDB exists and is ready\n\t connections \u003d system.db.getConnections()\n\t maria_conn \u003d next((c for c in connections if c.name \u003d\u003d \"MariaDB\"), None)\n\t \n\t if not maria_conn:\n\t print(\"❌ MariaDB connection not configured in Ignition\")\n\t self.props.data \u003d system.dataset.toDataSet([\"Error\"], [[\"Database connection \u0027MariaDB\u0027 not found\"]])\n\t return\n\t \n\t if maria_conn.status \u003d\u003d \"Disabled\":\n\t print(\"⚠️ MariaDB is disabled - attempting to enable...\")\n\t system.db.enableConnection(\"MariaDB\")\n\t system.util.sleep(2000) # Wait for connection attempt\n\t \n\t if maria_conn.status !\u003d \"Connected\":\n\t error_msg \u003d \"MariaDB status: {}\".format(maria_conn.status)\n\t print(error_msg)\n\t self.props.data \u003d system.dataset.toDataSet([\"Error\"], [[error_msg]])\n\t return\n\t \n\t # Quick ping test (3 second timeout)\n\t if not system.db.ping(\"MariaDB\", 3000):\n\t raise Exception(\"Database not responding to ping\")\n\t \n\texcept Exception as e:\n\t error_msg \u003d \"Database connection failed: {}\".format(str(e))\n\t print(error_msg)\n\t self.props.data \u003d system.dataset.toDataSet([\"Error\"], [[error_msg]])\n\t return\n\t\n\t\n\t# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n\t# 2. Original Logic (Wrapped in Try Block)\n\t# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n\ttry:\n\t path \u003d \"\"\n\t headers \u003d []\n\t rows \u003d []\n\t\n\t # Define the appropriate path based on the selected aggregation mode\n\t mode \u003d self.parent.parent.parent.getChild(\"Aggregation_Mode\").getChild(\"Dropdown_Aggregation_mode\").props.value\n\t if mode \u003d\u003d \"Count\":\n\t path \u003d \"Statistics/Hourly Induct Count\"\n\t headers \u003d [\"Start Timestamp\", \"Hour\", \"Total (#)\"]\n\t self.getSibling(\"Hourly Induct\").props.series[0].tooltip.text \u003d \"Total (#): [bold]{valueY}[/]\"\n\t self.getSibling(\"Hourly Induct\").props.yAxes[0].value.range.max \u003d \"\"\n\t elif mode \u003d\u003d \"Percentage\":\n\t path \u003d \"Statistics/Hourly Induct Percent\"\n\t headers \u003d [\"Start Timestamp\", \"Hour\", \"Total (%)\"]\n\t self.getSibling(\"Hourly Induct\").props.series[0].tooltip.text \u003d \"Total (%): [bold]{valueY}[/]%\"\n\t self.getSibling(\"Hourly Induct\").props.yAxes[0].value.range.max \u003d 100\n\t else:\n\t path \u003d \"Statistics/Hourly Induct Rate\"\n\t headers \u003d [\"Start Timestamp\", \"Hour\", \"Total (pph)\"]\n\t self.getSibling(\"Hourly Induct\").props.series[0].tooltip.text \u003d \"Total (pph): [bold]{valueY}[/] pph\"\n\t self.getSibling(\"Hourly Induct\").props.yAxes[0].value.range.max \u003d \"\"\n\t\n\t # Fetch the data from the database\n\t params \u003d {\n\t \"starttime\": self.parent.parent.parent.getChild(\"Period_not_Global_0\").custom.StartDate, \n\t \"endtime\": self.parent.parent.parent.getChild(\"Period_not_Global_0\").custom.EndDate\n\t }\n\t data \u003d system.dataset.toPyDataSet(system.db.runNamedQuery(path, params))\n\t\n\t # Prepare the rows for the dataset without \u0027SingleCarrier\u0027 and \u0027DoubleCarrier\u0027\n\t for row in data:\n\t row_data \u003d [row[\u0027StartTimestamp\u0027], row[\u0027Hour\u0027]]\n\t \n\t if mode \u003d\u003d \"Count\":\n\t row_data.append(row[\u0027Total_count\u0027])\n\t elif mode \u003d\u003d \"Percentage\":\n\t row_data.append(row[\u0027Total_percentage\u0027])\n\t else:\n\t row_data.append(row[\u0027Total_pph\u0027])\n\t\n\t if \u0027SingleCarrier\u0027 in row and row[\u0027SingleCarrier\u0027] is not None:\n\t row_data.append(row[\u0027SingleCarrier\u0027])\n\t headers.append(\"Single Carrier (#)\")\n\t if \u0027DoubleCarrier\u0027 in row and row[\u0027DoubleCarrier\u0027] is not None:\n\t row_data.append(row[\u0027DoubleCarrier\u0027])\n\t headers.append(\"Double Carrier (#)\")\n\t\n\t rows.append(row_data)\n\t\n\t # Filter headers and rows to exclude unwanted columns\n\t filtered_headers \u003d [h for h in headers if h not in [\"Single Carrier (#)\", \"Double Carrier (#)\"]]\n\t filtered_rows \u003d [\n\t [val for idx, val in enumerate(r) if headers[idx] not in [\"Single Carrier (#)\", \"Double Carrier (#)\"]]\n\t for r in rows\n\t ]\n\t\n\t dataset \u003d system.dataset.toDataSet(filtered_headers, filtered_rows)\n\t\n\t # Update the dataset and chart data\n\t self.props.data \u003d dataset\n\t self.getSibling(\"Hourly Induct\").props.dataSources.example \u003d dataset\n\t\n\texcept Exception as e:\n\t error_msg \u003d \"Query failed: {}\".format(str(e))\n\t print(\"🚨 {}\".format(error_msg))\n\t self.props.data \u003d system.dataset.toDataSet([\"Error\"], [[error_msg]])" + "script": " db_tag_path \u003d \"[System]Gateway/Database/MariaDB/Available\"\n\t\n if(system.tag.readBlocking([db_tag_path])[0].value):\n\t path \u003d \"\"\n\t headers \u003d []\n\t rows \u003d []\n\t\n\t # Define the appropriate path based on the selected aggregation mode\n\t mode \u003d self.parent.parent.parent.getChild(\"Aggregation_Mode\").getChild(\"Dropdown_Aggregation_mode\").props.value\n\t if mode \u003d\u003d \"Count\":\n\t path \u003d \"Statistics/Hourly Induct Count\"\n\t headers \u003d [\"Start Timestamp\", \"Hour\", \"Total (#)\"]\n\t self.getSibling(\"Hourly Induct\").props.series[0].tooltip.text \u003d \"Total (#): [bold]{valueY}[/]\"\n\t self.getSibling(\"Hourly Induct\").props.yAxes[0].value.range.max \u003d \"\"\n\t elif mode \u003d\u003d \"Percentage\":\n\t path \u003d \"Statistics/Hourly Induct Percent\"\n\t headers \u003d [\"Start Timestamp\", \"Hour\", \"Total (%)\"]\n\t self.getSibling(\"Hourly Induct\").props.series[0].tooltip.text \u003d \"Total (%): [bold]{valueY}[/]%\"\n\t self.getSibling(\"Hourly Induct\").props.yAxes[0].value.range.max \u003d 100\n\t else:\n\t path \u003d \"Statistics/Hourly Induct Rate\"\n\t headers \u003d [\"Start Timestamp\", \"Hour\", \"Total (pph)\"]\n\t self.getSibling(\"Hourly Induct\").props.series[0].tooltip.text \u003d \"Total (pph): [bold]{valueY}[/] pph\"\n\t self.getSibling(\"Hourly Induct\").props.yAxes[0].value.range.max \u003d \"\"\n\t\n\t # Fetch the data from the database\n\t params \u003d {\n\t \"starttime\": self.parent.parent.parent.getChild(\"Period_not_Global_0\").custom.StartDate, \n\t \"endtime\": self.parent.parent.parent.getChild(\"Period_not_Global_0\").custom.EndDate\n\t }\n\t data \u003d system.dataset.toPyDataSet(system.db.runNamedQuery(path, params))\n\t\n\t # Prepare the rows for the dataset without \u0027SingleCarrier\u0027 and \u0027DoubleCarrier\u0027\n\t for row in data:\n\t row_data \u003d [row[\u0027StartTimestamp\u0027], row[\u0027Hour\u0027]]\n\t \n\t if mode \u003d\u003d \"Count\":\n\t row_data.append(row[\u0027Total_count\u0027])\n\t elif mode \u003d\u003d \"Percentage\":\n\t row_data.append(row[\u0027Total_percentage\u0027])\n\t else:\n\t row_data.append(row[\u0027Total_pph\u0027])\n\t\n\t if \u0027SingleCarrier\u0027 in row and row[\u0027SingleCarrier\u0027] is not None:\n\t row_data.append(row[\u0027SingleCarrier\u0027])\n\t headers.append(\"Single Carrier (#)\")\n\t if \u0027DoubleCarrier\u0027 in row and row[\u0027DoubleCarrier\u0027] is not None:\n\t row_data.append(row[\u0027DoubleCarrier\u0027])\n\t headers.append(\"Double Carrier (#)\")\n\t\n\t rows.append(row_data)\n\t\n\t # Filter headers and rows to exclude unwanted columns\n\t filtered_headers \u003d [h for h in headers if h not in [\"Single Carrier (#)\", \"Double Carrier (#)\"]]\n\t filtered_rows \u003d [\n\t [val for idx, val in enumerate(r) if headers[idx] not in [\"Single Carrier (#)\", \"Double Carrier (#)\"]]\n\t for r in rows\n\t ]\n\t\n\t dataset \u003d system.dataset.toDataSet(filtered_headers, filtered_rows)\n\t\n\t # Update the dataset and chart data\n\t self.props.data \u003d dataset\n\t self.getSibling(\"Hourly Induct\").props.dataSources.example \u003d dataset\n\t" } }, "custom.time": { @@ -2134,14 +2162,22 @@ "$": [ "ds", 192, - 1747403903262 + 1747664567758 ], "$columns": [ { - "data": [ - "Database connection failed: \u0027com.inductiveautomation.ignition.common.BasicDataset\u0027 object is not iterable" - ], - "name": "Error", + "data": [], + "name": "Start Timestamp", + "type": "String" + }, + { + "data": [], + "name": "Hour", + "type": "String" + }, + { + "data": [], + "name": "Total (#)", "type": "String" } ] @@ -2178,7 +2214,7 @@ "$": [ "ds", 192, - 1747402203240 + 1747664567758 ], "$columns": [ { @@ -2936,7 +2972,7 @@ }, "onChange": { "enabled": null, - "script": "\t# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n\t# 1. Database Connection Check\n\t# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n\ttry:\n\t connections \u003d system.db.getConnections()\n\t maria_conn \u003d next((c for c in connections if c.name \u003d\u003d \"MariaDB\"), None)\n\t\n\t if not maria_conn:\n\t print(\"❌ MariaDB connection not configured in Ignition\")\n\t self.props.data \u003d system.dataset.toDataSet([\"Error\"], [[\"Database connection \u0027MariaDB\u0027 not found\"]])\n\t return\n\t\n\t if maria_conn.status \u003d\u003d \"Disabled\":\n\t print(\"⚠️ MariaDB is disabled - attempting to enable...\")\n\t system.db.enableConnection(\"MariaDB\")\n\t system.util.sleep(2000)\n\t\n\t if maria_conn.status !\u003d \"Connected\":\n\t error_msg \u003d \"MariaDB status: {maria_conn.status}\"\n\t print(error_msg)\n\t self.props.data \u003d system.dataset.toDataSet([\"Error\"], [[error_msg]])\n\t return\n\t\n\t if not system.db.ping(\"MariaDB\", 3000):\n\t raise Exception(\"Database not responding to ping\")\n\t\n\texcept Exception as e:\n\t error_msg \u003d \"Database connection failed: {str(e)}\"\n\t print(error_msg)\n\t self.props.data \u003d system.dataset.toDataSet([\"Error\"], [[error_msg]])\n\t return\n\t\n\t# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n\t# 2. Original Logic\n\t# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n\ttry:\n\t path \u003d \"\"\n\t headers \u003d []\n\t graph \u003d []\n\t\n\t mode \u003d self.parent.parent.parent.getChild(\"Aggregation_Mode\").getChild(\"Dropdown_Aggregation_mode\").props.value\n\t\n\t if mode \u003d\u003d \"Count\":\n\t path \u003d \"Statistics/Hourly Sorter Summary Count\"\n\t headers \u003d [\"Start Timestamp\", \"Hour\", \"Inducted (#)\", \"Sorted (#)\", \"Awcs Recirc (#)\", \"Operational Recirc (#)\", \"Machine Recirc (#)\"]\n\t self.getSibling(\"Hourly Sorter Summary\").props.series[0].tooltip.text \u003d \"Sorted (#): [bold]{valueY}[/]\"\n\t self.getSibling(\"Hourly Sorter Summary\").props.series[1].tooltip.text \u003d \"Awcs Recirc (#): [bold]{valueY}[/]\"\n\t self.getSibling(\"Hourly Sorter Summary\").props.series[2].tooltip.text \u003d \"Operational Recirc (#): [bold]{valueY}[/]\"\n\t self.getSibling(\"Hourly Sorter Summary\").props.series[3].tooltip.text \u003d \"Machine Recirc (#): [bold]{valueY}[/]\"\n\t self.getSibling(\"Hourly Sorter Summary\").props.yAxes[0].value.range.max \u003d \"\"\n\t elif mode \u003d\u003d \"Percentage\":\n\t path \u003d \"Statistics/Hourly Sorter Summary Percent\"\n\t headers \u003d [\"Start Timestamp\", \"Hour\", \"Inducted (%)\", \"Sorted (%)\", \"Awcs Recirc (%)\", \"Operational Recirc (%)\", \"Machine Recirc (%)\"]\n\t self.getSibling(\"Hourly Sorter Summary\").props.series[0].tooltip.text \u003d \"Sorted (%): [bold]{valueY}[/]%\"\n\t self.getSibling(\"Hourly Sorter Summary\").props.series[1].tooltip.text \u003d \"Awcs Recirc (%): [bold]{valueY}[/]%\"\n\t self.getSibling(\"Hourly Sorter Summary\").props.series[2].tooltip.text \u003d \"Operational Recirc (%): [bold]{valueY}[/]%\"\n\t self.getSibling(\"Hourly Sorter Summary\").props.series[3].tooltip.text \u003d \"Machine Recirc (%): [bold]{valueY}[/]%\"\n\t self.getSibling(\"Hourly Sorter Summary\").props.yAxes[0].value.range.max \u003d 100\n\t else:\n\t path \u003d \"Statistics/Hourly Sorter Summary Rate\"\n\t headers \u003d [\"Start Timestamp\", \"Hour\", \"Inducted (pph)\", \"Sorted (pph)\", \"Awcs Recirc (pph)\", \"Operational Recirc (pph)\", \"Machine Recirc (pph)\"]\n\t self.getSibling(\"Hourly Sorter Summary\").props.series[0].tooltip.text \u003d \"Sorted (pph): [bold]{valueY}[/] pph\"\n\t self.getSibling(\"Hourly Sorter Summary\").props.series[1].tooltip.text \u003d \"Awcs Recirc (pph): [bold]{valueY}[/] pph\"\n\t self.getSibling(\"Hourly Sorter Summary\").props.series[2].tooltip.text \u003d \"Operational Recirc (pph): [bold]{valueY}[/] pph\"\n\t self.getSibling(\"Hourly Sorter Summary\").props.series[3].tooltip.text \u003d \"Machine Recirc (pph): [bold]{valueY}[/] pph\"\n\t self.getSibling(\"Hourly Sorter Summary\").props.yAxes[0].value.range.max \u003d \"\"\n\t\n\t params \u003d {\n\t \"starttime\": self.parent.parent.parent.getChild(\"Period_not_Global_0\").custom.StartDate,\n\t \"endtime\": self.parent.parent.parent.getChild(\"Period_not_Global_0\").custom.EndDate\n\t }\n\t\n\t data \u003d system.dataset.toPyDataSet(system.db.runNamedQuery(path, params))\n\t\n\t for row in data:\n\t entry \u003d {\n\t \"Hour\": row[\"Hour\"],\n\t \"Sorted\": row[\"Sorted\"],\n\t \"AwcsRecirc\": row[\"AwcsRecirc\"],\n\t \"OperationalRecirc\": row[\"OperationalRecirc\"],\n\t \"MachineRecirc\": row[\"MachineRecirc\"]\n\t }\n\t graph.append(entry)\n\t\n\t self.getSibling(\"Hourly Sorter Summary\").props.dataSources.example \u003d graph\n\t self.props.data \u003d system.dataset.toDataSet(headers, data)\n\t\n\texcept Exception as e:\n\t error_msg \u003d \"Query failed: {str(e)}\"\n\t print(\"🚨 {error_msg}\")\n\t self.props.data \u003d system.dataset.toDataSet([\"Error\"], [[error_msg]])" + "script": " db_tag_path \u003d \"[System]Gateway/Database/MariaDB/Available\"\n\t\n if(system.tag.readBlocking([db_tag_path])[0].value):\n\t path \u003d \"\"\n\t headers \u003d []\n\t graph \u003d []\n\t\n\t mode \u003d self.parent.parent.parent.getChild(\"Aggregation_Mode\").getChild(\"Dropdown_Aggregation_mode\").props.value\n\t\n\t if mode \u003d\u003d \"Count\":\n\t path \u003d \"Statistics/Hourly Sorter Summary Count\"\n\t headers \u003d [\"Start Timestamp\", \"Hour\", \"Inducted (#)\", \"Sorted (#)\", \"Awcs Recirc (#)\", \"Operational Recirc (#)\", \"Machine Recirc (#)\"]\n\t self.getSibling(\"Hourly Sorter Summary\").props.series[0].tooltip.text \u003d \"Sorted (#): [bold]{valueY}[/]\"\n\t self.getSibling(\"Hourly Sorter Summary\").props.series[1].tooltip.text \u003d \"Awcs Recirc (#): [bold]{valueY}[/]\"\n\t self.getSibling(\"Hourly Sorter Summary\").props.series[2].tooltip.text \u003d \"Operational Recirc (#): [bold]{valueY}[/]\"\n\t self.getSibling(\"Hourly Sorter Summary\").props.series[3].tooltip.text \u003d \"Machine Recirc (#): [bold]{valueY}[/]\"\n\t self.getSibling(\"Hourly Sorter Summary\").props.yAxes[0].value.range.max \u003d \"\"\n\t elif mode \u003d\u003d \"Percentage\":\n\t path \u003d \"Statistics/Hourly Sorter Summary Percent\"\n\t headers \u003d [\"Start Timestamp\", \"Hour\", \"Inducted (%)\", \"Sorted (%)\", \"Awcs Recirc (%)\", \"Operational Recirc (%)\", \"Machine Recirc (%)\"]\n\t self.getSibling(\"Hourly Sorter Summary\").props.series[0].tooltip.text \u003d \"Sorted (%): [bold]{valueY}[/]%\"\n\t self.getSibling(\"Hourly Sorter Summary\").props.series[1].tooltip.text \u003d \"Awcs Recirc (%): [bold]{valueY}[/]%\"\n\t self.getSibling(\"Hourly Sorter Summary\").props.series[2].tooltip.text \u003d \"Operational Recirc (%): [bold]{valueY}[/]%\"\n\t self.getSibling(\"Hourly Sorter Summary\").props.series[3].tooltip.text \u003d \"Machine Recirc (%): [bold]{valueY}[/]%\"\n\t self.getSibling(\"Hourly Sorter Summary\").props.yAxes[0].value.range.max \u003d 100\n\t else:\n\t path \u003d \"Statistics/Hourly Sorter Summary Rate\"\n\t headers \u003d [\"Start Timestamp\", \"Hour\", \"Inducted (pph)\", \"Sorted (pph)\", \"Awcs Recirc (pph)\", \"Operational Recirc (pph)\", \"Machine Recirc (pph)\"]\n\t self.getSibling(\"Hourly Sorter Summary\").props.series[0].tooltip.text \u003d \"Sorted (pph): [bold]{valueY}[/] pph\"\n\t self.getSibling(\"Hourly Sorter Summary\").props.series[1].tooltip.text \u003d \"Awcs Recirc (pph): [bold]{valueY}[/] pph\"\n\t self.getSibling(\"Hourly Sorter Summary\").props.series[2].tooltip.text \u003d \"Operational Recirc (pph): [bold]{valueY}[/] pph\"\n\t self.getSibling(\"Hourly Sorter Summary\").props.series[3].tooltip.text \u003d \"Machine Recirc (pph): [bold]{valueY}[/] pph\"\n\t self.getSibling(\"Hourly Sorter Summary\").props.yAxes[0].value.range.max \u003d \"\"\n\t\n\t params \u003d {\n\t \"starttime\": self.parent.parent.parent.getChild(\"Period_not_Global_0\").custom.StartDate,\n\t \"endtime\": self.parent.parent.parent.getChild(\"Period_not_Global_0\").custom.EndDate\n\t }\n\t\n\t data \u003d system.dataset.toPyDataSet(system.db.runNamedQuery(path, params))\n\t\n\t for row in data:\n\t entry \u003d {\n\t \"Hour\": row[\"Hour\"],\n\t \"Sorted\": row[\"Sorted\"],\n\t \"AwcsRecirc\": row[\"AwcsRecirc\"],\n\t \"OperationalRecirc\": row[\"OperationalRecirc\"],\n\t \"MachineRecirc\": row[\"MachineRecirc\"]\n\t }\n\t graph.append(entry)\n\t\n\t self.getSibling(\"Hourly Sorter Summary\").props.dataSources.example \u003d graph\n\t self.props.data \u003d system.dataset.toDataSet(headers, data)\n" } }, "custom.time": { @@ -3499,14 +3535,42 @@ "$": [ "ds", 192, - 1747403903257 + 1747664567746 ], "$columns": [ { - "data": [ - "Database connection failed: {str(e)}" - ], - "name": "Error", + "data": [], + "name": "Start Timestamp", + "type": "String" + }, + { + "data": [], + "name": "Hour", + "type": "String" + }, + { + "data": [], + "name": "Inducted (#)", + "type": "String" + }, + { + "data": [], + "name": "Sorted (#)", + "type": "String" + }, + { + "data": [], + "name": "Awcs Recirc (#)", + "type": "String" + }, + { + "data": [], + "name": "Operational Recirc (#)", + "type": "String" + }, + { + "data": [], + "name": "Machine Recirc (#)", "type": "String" } ] @@ -4791,7 +4855,7 @@ }, "onChange": { "enabled": null, - "script": "\t# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n\t# 1. Database Connection Check\n\t# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n\ttry:\n\t # Check if MariaDB exists and is ready\n\t connections \u003d system.db.getConnections()\n\t maria_conn \u003d next((c for c in connections if c.name \u003d\u003d \"MariaDB\"), None)\n\t \n\t if not maria_conn:\n\t print(\"❌ MariaDB connection not configured in Ignition\")\n\t self.props.data \u003d system.dataset.toDataSet([\"Error\"], [[\"Database connection \u0027MariaDB\u0027 not found\"]])\n\t return\n\t \n\t if maria_conn.status \u003d\u003d \"Disabled\":\n\t print(\"⚠️ MariaDB is disabled - attempting to enable...\")\n\t system.db.enableConnection(\"MariaDB\")\n\t system.util.sleep(2000) # Wait for connection attempt\n\t \n\t if maria_conn.status !\u003d \"Connected\":\n\t error_msg \u003d \"MariaDB status: {}\".format(maria_conn.status)\n\t print(\"{}\".format(error_msg))\n\t self.props.data \u003d system.dataset.toDataSet([\"Error\"], [[error_msg]])\n\t return\n\t \n\t # Quick ping test (3 second timeout)\n\t if not system.db.ping(\"MariaDB\", 3000):\n\t raise Exception(\"Database not responding to ping\")\n\t \n\texcept Exception as e:\n\t error_msg \u003d \"Database connection failed: {}\".format(str(e))\n\t print(\"{}\".format(error_msg))\n\t self.props.data \u003d system.dataset.toDataSet([\"Error\"], [[error_msg]])\n\t return\n\t\n\t# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n\t# 2. Original Logic (Protected)\n\t# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n\ttry:\n\t path \u003d \"\"\n\t headers \u003d []\n\t graph \u003d []\n\t\n\t if self.parent.parent.parent.getChild(\"Aggregation_Mode\").getChild(\"Dropdown_Aggregation_mode\").props.value \u003d\u003d \"Count\":\n\t path \u003d \"Statistics/Hourly Sorter Details Count\"\n\t headers \u003d [\"Start Timestamp\",\"Hour\",\"Inducted (#)\",\"Sorted (#)\",\"Dest Inv (#)\",\"Dest None (#)\",\"Dest Dis (#)\",\"Dest Full (#)\",\"Unexpected (#)\",\"Dest Fault (#)\",\"Div Fail (#)\",\"Gap Err (#)\",\"Lost (#)\",\"Track Err (#)\",\"Unknown (#)\",\"Unsafe (#)\"]\n\t self.getSibling(\"Hourly Sorter Details\").props.series[0].tooltip.text \u003d \"Sorted (#): [bold]{valueY}[/]\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[1].tooltip.text \u003d \"Dest Invalid (#): [bold]{valueY}[/]\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[2].tooltip.text \u003d \"Dest None (#): [bold]{valueY}[/]\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[3].tooltip.text \u003d \"Dest Disabled (#): [bold]{valueY}[/]\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[4].tooltip.text \u003d \"Dest Full (#): [bold]{valueY}[/]\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[5].tooltip.text \u003d \"Unexpected (#): [bold]{valueY}[/]\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[6].tooltip.text \u003d \"Dest Fault (#): [bold]{valueY}[/]\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[7].tooltip.text \u003d \"Div Fail (#): [bold]{valueY}[/]\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[8].tooltip.text \u003d \"Gap Error (#): [bold]{valueY}[/]\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[9].tooltip.text \u003d \"Lost (#): [bold]{valueY}[/]\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[10].tooltip.text \u003d \"Tracking Err (#): [bold]{valueY}[/]\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[11].tooltip.text \u003d \"Unknown (#): [bold]{valueY}[/]\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[12].tooltip.text \u003d \"Unsafe (#): [bold]{valueY}[/]\"\n\t self.getSibling(\"Hourly Sorter Details\").props.yAxes[0].value.range.max \u003d \"\"\n\t elif self.parent.parent.parent.getChild(\"Aggregation_Mode\").getChild(\"Dropdown_Aggregation_mode\").props.value \u003d\u003d \"Percentage\":\n\t path \u003d \"Statistics/Hourly Sorter Details Percent\"\n\t headers \u003d [\"Start Timestamp\",\"Hour\",\"Inducted (%)\",\"Sorted (%)\",\"Dest Inv (%)\",\"Dest None (%)\",\"Dest Dis (%)\",\"Dest Full (%)\",\"Unexpected (%)\",\"Dest Fault (%)\",\"Div Fail (%)\",\"Gap Err (%)\",\"Lost (%)\",\"Track Err (%)\",\"Unknown (%)\",\"Unsafe (%)\"]\n\t self.getSibling(\"Hourly Sorter Details\").props.series[0].tooltip.text \u003d \"Sorted (%): [bold]{valueY}[/]%\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[1].tooltip.text \u003d \"Dest Invalid (%): [bold]{valueY}[/]%\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[2].tooltip.text \u003d \"Dest None (%): [bold]{valueY}[/]%\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[3].tooltip.text \u003d \"Dest Disabled (%): [bold]{valueY}[/]%\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[4].tooltip.text \u003d \"Dest Full (%): [bold]{valueY}[/]%\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[5].tooltip.text \u003d \"Unexpected (%): [bold]{valueY}[/]%\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[6].tooltip.text \u003d \"Dest Fault (%): [bold]{valueY}[/]%\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[7].tooltip.text \u003d \"Div Fail (%): [bold]{valueY}[/]%\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[8].tooltip.text \u003d \"Gap Error (%): [bold]{valueY}[/]%\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[9].tooltip.text \u003d \"Lost (%): [bold]{valueY}[/]%\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[10].tooltip.text \u003d \"Tracking Err (%): [bold]{valueY}[/]%\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[11].tooltip.text \u003d \"Unknown (%): [bold]{valueY}[/]%\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[12].tooltip.text \u003d \"Unsafe (%): [bold]{valueY}[/]%\"\n\t self.getSibling(\"Hourly Sorter Details\").props.yAxes[0].value.range.max \u003d 100\n\t else:\n\t path \u003d \"Statistics/Hourly Sorter Details Rate\"\n\t headers \u003d [\"Start Timestamp\",\"Hour\",\"Inducted (pph)\",\"Sorted (pph)\",\"Dest Inv (pph)\",\"Dest None (pph)\",\"Dest Dis (pph)\",\"Dest Full (pph)\",\"Unexpected (pph)\",\"Dest Fault (pph)\",\"Div Fail (pph)\",\"Gap Err (pph)\",\"Lost (pph)\",\"Track Err (pph)\",\"Unknown (pph)\",\"Unsafe (pph)\"]\n\t self.getSibling(\"Hourly Sorter Details\").props.series[0].tooltip.text \u003d \"Sorted (pph): [bold]{valueY}[/]pph\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[1].tooltip.text \u003d \"Dest Invalid (pph): [bold]{valueY}[/]pph\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[2].tooltip.text \u003d \"Dest None (pph): [bold]{valueY}[/] pph\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[3].tooltip.text \u003d \"Dest Disabled (pph): [bold]{valueY}[/]pph\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[4].tooltip.text \u003d \"Dest Full (pph): [bold]{valueY}[/]pph\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[5].tooltip.text \u003d \"Unexpected (pph): [bold]{valueY}[/]pph\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[6].tooltip.text \u003d \"Dest Fault (pph): [bold]{valueY}[/]pph\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[7].tooltip.text \u003d \"Div Fail (pph): [bold]{valueY}[/]pph\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[8].tooltip.text \u003d \"Gap Error (pph): [bold]{valueY}[/]pph\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[9].tooltip.text \u003d \"Lost (pph): [bold]{valueY}[/]pph\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[10].tooltip.text \u003d \"Tracking Err (pph): [bold]{valueY}[/]pph\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[11].tooltip.text \u003d \"Unknown (pph): [bold]{valueY}[/]pph\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[12].tooltip.text \u003d \"Unsafe (pph): [bold]{valueY}[/]pph\"\n\t self.getSibling(\"Hourly Sorter Details\").props.yAxes[0].value.range.max \u003d \"\"\n\t\n\t params \u003d {\n\t \"starttime\": self.parent.parent.parent.getChild(\"Period_not_Global_0\").custom.StartDate,\n\t \"endtime\": self.parent.parent.parent.getChild(\"Period_not_Global_0\").custom.EndDate\n\t }\n\t\n\t data \u003d system.dataset.toPyDataSet(system.db.runNamedQuery(path, params))\n\t\n\t for row in data:\n\t dict \u003d {}\n\t dict[\u0027Hour\u0027] \u003d row[\u0027Hour\u0027]\n\t dict[\u0027Sorted\u0027] \u003d row[\u0027Sorted\u0027]\n\t dict[\u0027DestinationInvalid\u0027] \u003d row[\u0027DestinationInvalid\u0027]\n\t dict[\u0027DestinationNone\u0027] \u003d row[\u0027DestinationNone\u0027]\n\t dict[\u0027DestinationDisabled\u0027] \u003d row[\u0027DestinationDisabled\u0027]\n\t dict[\u0027DestinationFull\u0027] \u003d row[\u0027DestinationFull\u0027]\n\t dict[\u0027Unexpected\u0027] \u003d row[\u0027Unexpected\u0027]\n\t dict[\u0027DestinationFault\u0027] \u003d row[\u0027DestinationFault\u0027]\n\t dict[\u0027DivertFail\u0027] \u003d row[\u0027DivertFail\u0027]\n\t dict[\u0027GapError\u0027] \u003d row[\u0027GapError\u0027]\n\t dict[\u0027Lost\u0027] \u003d row[\u0027Lost\u0027]\n\t dict[\u0027TrackingError\u0027] \u003d row[\u0027TrackingError\u0027]\n\t dict[\u0027Unknown\u0027] \u003d row[\u0027Unknown\u0027]\n\t dict[\u0027Unsafe\u0027] \u003d row[\u0027Unsafe\u0027]\n\t graph.append(dict)\n\t\n\t self.getSibling(\"Hourly Sorter Details\").props.dataSources.example \u003d graph\n\t self.props.data \u003d system.dataset.toDataSet(headers, data)\n\t\n\texcept Exception as e:\n\t error_msg \u003d \"Query failed: {}\".format(str(e))\n\t print(\"🚨 {}\".format(error_msg))\n\t self.props.data \u003d system.dataset.toDataSet([\"Error\"], [[error_msg]])" + "script": " db_tag_path \u003d \"[System]Gateway/Database/MariaDB/Available\"\n\t\n if(system.tag.readBlocking([db_tag_path])[0].value):\n\t path \u003d \"\"\n\t headers \u003d []\n\t graph \u003d []\n\t\n\t if self.parent.parent.parent.getChild(\"Aggregation_Mode\").getChild(\"Dropdown_Aggregation_mode\").props.value \u003d\u003d \"Count\":\n\t path \u003d \"Statistics/Hourly Sorter Details Count\"\n\t headers \u003d [\"Start Timestamp\",\"Hour\",\"Inducted (#)\",\"Sorted (#)\",\"Dest Inv (#)\",\"Dest None (#)\",\"Dest Dis (#)\",\"Dest Full (#)\",\"Unexpected (#)\",\"Dest Fault (#)\",\"Div Fail (#)\",\"Gap Err (#)\",\"Lost (#)\",\"Track Err (#)\",\"Unknown (#)\",\"Unsafe (#)\"]\n\t self.getSibling(\"Hourly Sorter Details\").props.series[0].tooltip.text \u003d \"Sorted (#): [bold]{valueY}[/]\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[1].tooltip.text \u003d \"Dest Invalid (#): [bold]{valueY}[/]\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[2].tooltip.text \u003d \"Dest None (#): [bold]{valueY}[/]\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[3].tooltip.text \u003d \"Dest Disabled (#): [bold]{valueY}[/]\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[4].tooltip.text \u003d \"Dest Full (#): [bold]{valueY}[/]\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[5].tooltip.text \u003d \"Unexpected (#): [bold]{valueY}[/]\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[6].tooltip.text \u003d \"Dest Fault (#): [bold]{valueY}[/]\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[7].tooltip.text \u003d \"Div Fail (#): [bold]{valueY}[/]\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[8].tooltip.text \u003d \"Gap Error (#): [bold]{valueY}[/]\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[9].tooltip.text \u003d \"Lost (#): [bold]{valueY}[/]\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[10].tooltip.text \u003d \"Tracking Err (#): [bold]{valueY}[/]\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[11].tooltip.text \u003d \"Unknown (#): [bold]{valueY}[/]\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[12].tooltip.text \u003d \"Unsafe (#): [bold]{valueY}[/]\"\n\t self.getSibling(\"Hourly Sorter Details\").props.yAxes[0].value.range.max \u003d \"\"\n\t elif self.parent.parent.parent.getChild(\"Aggregation_Mode\").getChild(\"Dropdown_Aggregation_mode\").props.value \u003d\u003d \"Percentage\":\n\t path \u003d \"Statistics/Hourly Sorter Details Percent\"\n\t headers \u003d [\"Start Timestamp\",\"Hour\",\"Inducted (%)\",\"Sorted (%)\",\"Dest Inv (%)\",\"Dest None (%)\",\"Dest Dis (%)\",\"Dest Full (%)\",\"Unexpected (%)\",\"Dest Fault (%)\",\"Div Fail (%)\",\"Gap Err (%)\",\"Lost (%)\",\"Track Err (%)\",\"Unknown (%)\",\"Unsafe (%)\"]\n\t self.getSibling(\"Hourly Sorter Details\").props.series[0].tooltip.text \u003d \"Sorted (%): [bold]{valueY}[/]%\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[1].tooltip.text \u003d \"Dest Invalid (%): [bold]{valueY}[/]%\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[2].tooltip.text \u003d \"Dest None (%): [bold]{valueY}[/]%\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[3].tooltip.text \u003d \"Dest Disabled (%): [bold]{valueY}[/]%\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[4].tooltip.text \u003d \"Dest Full (%): [bold]{valueY}[/]%\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[5].tooltip.text \u003d \"Unexpected (%): [bold]{valueY}[/]%\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[6].tooltip.text \u003d \"Dest Fault (%): [bold]{valueY}[/]%\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[7].tooltip.text \u003d \"Div Fail (%): [bold]{valueY}[/]%\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[8].tooltip.text \u003d \"Gap Error (%): [bold]{valueY}[/]%\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[9].tooltip.text \u003d \"Lost (%): [bold]{valueY}[/]%\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[10].tooltip.text \u003d \"Tracking Err (%): [bold]{valueY}[/]%\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[11].tooltip.text \u003d \"Unknown (%): [bold]{valueY}[/]%\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[12].tooltip.text \u003d \"Unsafe (%): [bold]{valueY}[/]%\"\n\t self.getSibling(\"Hourly Sorter Details\").props.yAxes[0].value.range.max \u003d 100\n\t else:\n\t path \u003d \"Statistics/Hourly Sorter Details Rate\"\n\t headers \u003d [\"Start Timestamp\",\"Hour\",\"Inducted (pph)\",\"Sorted (pph)\",\"Dest Inv (pph)\",\"Dest None (pph)\",\"Dest Dis (pph)\",\"Dest Full (pph)\",\"Unexpected (pph)\",\"Dest Fault (pph)\",\"Div Fail (pph)\",\"Gap Err (pph)\",\"Lost (pph)\",\"Track Err (pph)\",\"Unknown (pph)\",\"Unsafe (pph)\"]\n\t self.getSibling(\"Hourly Sorter Details\").props.series[0].tooltip.text \u003d \"Sorted (pph): [bold]{valueY}[/]pph\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[1].tooltip.text \u003d \"Dest Invalid (pph): [bold]{valueY}[/]pph\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[2].tooltip.text \u003d \"Dest None (pph): [bold]{valueY}[/] pph\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[3].tooltip.text \u003d \"Dest Disabled (pph): [bold]{valueY}[/]pph\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[4].tooltip.text \u003d \"Dest Full (pph): [bold]{valueY}[/]pph\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[5].tooltip.text \u003d \"Unexpected (pph): [bold]{valueY}[/]pph\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[6].tooltip.text \u003d \"Dest Fault (pph): [bold]{valueY}[/]pph\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[7].tooltip.text \u003d \"Div Fail (pph): [bold]{valueY}[/]pph\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[8].tooltip.text \u003d \"Gap Error (pph): [bold]{valueY}[/]pph\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[9].tooltip.text \u003d \"Lost (pph): [bold]{valueY}[/]pph\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[10].tooltip.text \u003d \"Tracking Err (pph): [bold]{valueY}[/]pph\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[11].tooltip.text \u003d \"Unknown (pph): [bold]{valueY}[/]pph\"\n\t self.getSibling(\"Hourly Sorter Details\").props.series[12].tooltip.text \u003d \"Unsafe (pph): [bold]{valueY}[/]pph\"\n\t self.getSibling(\"Hourly Sorter Details\").props.yAxes[0].value.range.max \u003d \"\"\n\t\n\t params \u003d {\n\t \"starttime\": self.parent.parent.parent.getChild(\"Period_not_Global_0\").custom.StartDate,\n\t \"endtime\": self.parent.parent.parent.getChild(\"Period_not_Global_0\").custom.EndDate\n\t }\n\t\n\t data \u003d system.dataset.toPyDataSet(system.db.runNamedQuery(path, params))\n\t\n\t for row in data:\n\t dict \u003d {}\n\t dict[\u0027Hour\u0027] \u003d row[\u0027Hour\u0027]\n\t dict[\u0027Sorted\u0027] \u003d row[\u0027Sorted\u0027]\n\t dict[\u0027DestinationInvalid\u0027] \u003d row[\u0027DestinationInvalid\u0027]\n\t dict[\u0027DestinationNone\u0027] \u003d row[\u0027DestinationNone\u0027]\n\t dict[\u0027DestinationDisabled\u0027] \u003d row[\u0027DestinationDisabled\u0027]\n\t dict[\u0027DestinationFull\u0027] \u003d row[\u0027DestinationFull\u0027]\n\t dict[\u0027Unexpected\u0027] \u003d row[\u0027Unexpected\u0027]\n\t dict[\u0027DestinationFault\u0027] \u003d row[\u0027DestinationFault\u0027]\n\t dict[\u0027DivertFail\u0027] \u003d row[\u0027DivertFail\u0027]\n\t dict[\u0027GapError\u0027] \u003d row[\u0027GapError\u0027]\n\t dict[\u0027Lost\u0027] \u003d row[\u0027Lost\u0027]\n\t dict[\u0027TrackingError\u0027] \u003d row[\u0027TrackingError\u0027]\n\t dict[\u0027Unknown\u0027] \u003d row[\u0027Unknown\u0027]\n\t dict[\u0027Unsafe\u0027] \u003d row[\u0027Unsafe\u0027]\n\t graph.append(dict)\n\t\n\t self.getSibling(\"Hourly Sorter Details\").props.dataSources.example \u003d graph\n\t self.props.data \u003d system.dataset.toDataSet(headers, data)\n\t" } }, "custom.time": { @@ -4813,14 +4877,87 @@ "$": [ "ds", 192, - 1747403903262 + 1747664567761 ], "$columns": [ { - "data": [ - "Database connection failed: \u0027com.inductiveautomation.ignition.common.BasicDataset\u0027 object is not iterable" - ], - "name": "Error", + "data": [], + "name": "Start Timestamp", + "type": "String" + }, + { + "data": [], + "name": "Hour", + "type": "String" + }, + { + "data": [], + "name": "Inducted (#)", + "type": "String" + }, + { + "data": [], + "name": "Sorted (#)", + "type": "String" + }, + { + "data": [], + "name": "Dest Inv (#)", + "type": "String" + }, + { + "data": [], + "name": "Dest None (#)", + "type": "String" + }, + { + "data": [], + "name": "Dest Dis (#)", + "type": "String" + }, + { + "data": [], + "name": "Dest Full (#)", + "type": "String" + }, + { + "data": [], + "name": "Unexpected (#)", + "type": "String" + }, + { + "data": [], + "name": "Dest Fault (#)", + "type": "String" + }, + { + "data": [], + "name": "Div Fail (#)", + "type": "String" + }, + { + "data": [], + "name": "Gap Err (#)", + "type": "String" + }, + { + "data": [], + "name": "Lost (#)", + "type": "String" + }, + { + "data": [], + "name": "Track Err (#)", + "type": "String" + }, + { + "data": [], + "name": "Unknown (#)", + "type": "String" + }, + { + "data": [], + "name": "Unsafe (#)", "type": "String" } ] @@ -8450,7 +8587,7 @@ }, "onChange": { "enabled": null, - "script": "\t\t\n\ttry:\n\t # Check if MariaDB exists and is ready\n\t connections \u003d system.db.getConnections()\n\t maria_conn \u003d next((c for c in connections if c.name \u003d\u003d \"MariaDB\"), None)\n\t \n\t if not maria_conn:\n\t print(\"❌ MariaDB connection not configured in Ignition\")\n\t self.props.data \u003d system.dataset.toDataSet([\"Error\"], [[\"Database connection \u0027MariaDB\u0027 not found\"]])\n\t return\n\t \n\t if maria_conn.status \u003d\u003d \"Disabled\":\n\t print(\"⚠️ MariaDB is disabled - attempting to enable...\")\n\t system.db.enableConnection(\"MariaDB\")\n\t system.util.sleep(2000) # Wait for connection attempt\n\t \n\t if maria_conn.status !\u003d \"Connected\":\n\t error_msg \u003d \"MariaDB status: {}\".format(maria_conn.status)\n\t print(\"{}\".format(error_msg))\n\t self.props.data \u003d system.dataset.toDataSet([\"Error\"], [[error_msg]])\n\t return\n\t \n\t # Quick ping test (3 second timeout)\n\t if not system.db.ping(\"MariaDB\", 3000):\n\t raise Exception(\"Database not responding to ping\")\n\t \n\texcept Exception as e:\n\t error_msg \u003d \"Database connection failed: {}\".format(str(e))\n\t print(\"{}\".format(error_msg))\n\t self.props.data \u003d system.dataset.toDataSet([\"Error\"], [[error_msg]])\n\t return\n\t\n\t\n\ttry:\n\t\t\n\t\n\t\tpath \u003d \"\"\n\t\theaders \u003d []\n\t\tgraph \u003d []\n\t\t\n\t\tif self.parent.parent.parent.getChild(\"Aggregation_Mode\").getChild(\"Dropdown_Aggregation_mode\").props.value \u003d\u003d \"Count\":\n\t\t\tpath \u003d \"Statistics/Hourly Lane Count\"\n\t\t\theaders \u003d [\"Start Timestamp\",\"Hour\",\"Total (#)\",\"Diverted (#)\",\"Dest Full (#)\",\"Dest Jam (#)\",\"Dest Disabled (#)\",\"Dest Fault (#)\",\"Divert Fail (#)\",\"Lost (#)\",\"Unsafe (#)\",\"Dim Err (#)\",\"Gap Err (#)\",\"Unknown (#)\"]\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[0].tooltip.text \u003d \"Diverted (#): [bold]{valueY}[/]\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[1].tooltip.text \u003d \"Dest Full (#): [bold]{valueY}[/]\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[2].tooltip.text \u003d \"Dest Jam (#): [bold]{valueY}[/]\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[3].tooltip.text \u003d \"Dest Disabled (#): [bold]{valueY}[/]\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[4].tooltip.text \u003d \"Dest Fault (#): [bold]{valueY}[/]\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[5].tooltip.text \u003d \"Divert Fail (#): [bold]{valueY}[/]\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[6].tooltip.text \u003d \"Lost (#): [bold]{valueY}[/]\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[7].tooltip.text \u003d \"Unsafe (#): [bold]{valueY}[/]\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[8].tooltip.text \u003d \"Dim Err (#): [bold]{valueY}[/]\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[9].tooltip.text \u003d \"Gap Err (#): [bold]{valueY}[/]\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[10].tooltip.text \u003d \"Unknown (#): [bold]{valueY}[/]\"\t\t\n\t\t\tself.getSibling(\"Hourly Lane\").props.yAxes[0].value.range.max \u003d \"\"\n\t\telif self.parent.parent.parent.getChild(\"Aggregation_Mode\").getChild(\"Dropdown_Aggregation_mode\").props.value \u003d\u003d \"Percentage\":\n\t\t\tpath \u003d \"Statistics/Hourly Lane Percent\"\n\t\t\theaders \u003d [\"Start Timestamp\",\"Hour\",\"Total (%)\",\"Diverted (%)\",\"Dest Full (%)\",\"Dest Jam (%)\",\"Dest Disabled (%)\",\"Dest Fault (%)\",\"Divert Fail (%)\",\"Lost (%)\",\"Unsafe (%)\",\"Dim Err (%)\",\"Gap Err (%)\",\"Unknown (%)\"]\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[0].tooltip.text \u003d \"Diverted (%): [bold]{valueY}[/]%\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[1].tooltip.text \u003d \"Dest Full (%): [bold]{valueY}[/]%\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[2].tooltip.text \u003d \"Dest Jam (%): [bold]{valueY}[/]%\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[3].tooltip.text \u003d \"Dest Disabled (%): [bold]{valueY}[/]%\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[4].tooltip.text \u003d \"Dest Fault (%): [bold]{valueY}[/]%\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[5].tooltip.text \u003d \"Divert Fail (%): [bold]{valueY}[/]%\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[6].tooltip.text \u003d \"Lost (%): [bold]{valueY}[/]%\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[7].tooltip.text \u003d \"Unsafe (%): [bold]{valueY}[/]%\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[8].tooltip.text \u003d \"Dim Err (%): [bold]{valueY}[/]%\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[9].tooltip.text \u003d \"Gap Err (%): [bold]{valueY}[/]%\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[10].tooltip.text \u003d \"Unknown (%): [bold]{valueY}[/]%\"\t\t\n\t\t\tself.getSibling(\"Hourly Lane\").props.yAxes[0].value.range.max \u003d 100\n\t\telse:\n\t\t\tpath \u003d \"Statistics/Hourly Lane Rate\"\n\t\t\theaders \u003d [\"Start Timestamp\",\"Hour\",\"Total (pph)\",\"Diverted (pph)\",\"Dest Full (pph)\",\"Dest Jam (pph)\",\"Dest Disabled (pph)\",\"Dest Fault (pph)\",\"Divert Fail (pph)\",\"Lost (pph)\",\"Unsafe (pph)\",\"Dim Err (pph)\",\"Gap Err (pph)\",\"Unknown (pph)\"]\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[0].tooltip.text \u003d \"Diverted (pph): [bold]{valueY}[/] pph\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[1].tooltip.text \u003d \"Dest Full (pph): [bold]{valueY}[/] pph\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[2].tooltip.text \u003d \"Dest Jam (pph): [bold]{valueY}[/] pph\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[3].tooltip.text \u003d \"Dest Disabled (pph): [bold]{valueY}[/] pph\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[4].tooltip.text \u003d \"Dest Fault (pph): [bold]{valueY}[/] pph\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[5].tooltip.text \u003d \"Divert Fail (pph): [bold]{valueY}[/] pph\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[6].tooltip.text \u003d \"Lost (pph): [bold]{valueY}[/] pph\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[7].tooltip.text \u003d \"Unsafe (pph): [bold]{valueY}[/] pph\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[8].tooltip.text \u003d \"Dim Err (pph): [bold]{valueY}[/] pph\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[9].tooltip.text \u003d \"Gap Err (pph): [bold]{valueY}[/] pph\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[10].tooltip.text \u003d \"Unknown (pph): [bold]{valueY}[/] pph\"\t\n\t\t\tself.getSibling(\"Hourly Lane\").props.yAxes[0].value.range.max \u003d \"\"\n\t\t\t\n\t\tparams \u003d {\"starttime\":self.parent.parent.parent.getChild(\"Period_not_Global_0\").custom.StartDate,\"endtime\":self.parent.parent.parent.getChild(\"Period_not_Global_0\").custom.EndDate,\"lane\":self.parent.parent.parent.getChild(\"Lane Drop Down\").getChild(\"Lane\").props.value}\t\n\t\t\n\t\tdata \u003d system.dataset.toPyDataSet(system.db.runNamedQuery(path,params))\n\t\t\n\t\tfor row in data:\t\n\t\t\tdict \u003d {}\n\t\t\tdict[\u0027Hour\u0027] \u003d \trow[\u0027Hour\u0027]\n\t\t\tdict[\u0027Diverted\u0027] \u003d row[\u0027Diverted\u0027]\n\t\t\tdict[\u0027DestinationFull\u0027] \u003d row[\u0027DestinationFull\u0027]\n\t\t\tdict[\u0027DestinationJam\u0027] \u003d row[\u0027DestinationJam\u0027]\n\t\t\tdict[\u0027DestinationDisabled\u0027] \u003d row[\u0027DestinationDisabled\u0027]\n\t\t\tdict[\u0027DestinationFault\u0027] \u003d row[\u0027DestinationFault\u0027]\n\t\t\tdict[\u0027DivertFail\u0027] \u003d row[\u0027DivertFail\u0027]\n\t\t\tdict[\u0027Lost\u0027] \u003d row[\u0027Lost\u0027]\n\t\t\tdict[\u0027Unsafe\u0027] \u003d row[\u0027Unsafe\u0027]\n\t\t\tdict[\u0027DimError\u0027] \u003d row[\u0027DimError\u0027]\n\t\t\tdict[\u0027GapError\u0027] \u003d row[\u0027GapError\u0027]\n\t\t\tdict[\u0027Unknown\u0027] \u003d row[\u0027Unknown\u0027]\n\t\t\tgraph.append(dict)\n\t\t\n\t\tself.getSibling(\"Hourly Lane\").props.dataSources.example \u003d graph\n\t\tself.props.data \u003d system.dataset.toDataSet(headers,data)\n\texcept Exception as e:\n\t error_msg \u003d \"Query failed: {}\".format(str(e))\n\t print(\"🚨 {}\".format(error_msg))\n\t self.props.data \u003d system.dataset.toDataSet([\"Error\"], [[error_msg]])" + "script": " db_tag_path \u003d \"[System]Gateway/Database/MariaDB/Available\"\n\t\n if(system.tag.readBlocking([db_tag_path])[0].value):\n\t\tpath \u003d \"\"\n\t\theaders \u003d []\n\t\tgraph \u003d []\n\t\t\n\t\tif self.parent.parent.parent.getChild(\"Aggregation_Mode\").getChild(\"Dropdown_Aggregation_mode\").props.value \u003d\u003d \"Count\":\n\t\t\tpath \u003d \"Statistics/Hourly Lane Count\"\n\t\t\theaders \u003d [\"Start Timestamp\",\"Hour\",\"Total (#)\",\"Diverted (#)\",\"Dest Full (#)\",\"Dest Jam (#)\",\"Dest Disabled (#)\",\"Dest Fault (#)\",\"Divert Fail (#)\",\"Lost (#)\",\"Unsafe (#)\",\"Dim Err (#)\",\"Gap Err (#)\",\"Unknown (#)\"]\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[0].tooltip.text \u003d \"Diverted (#): [bold]{valueY}[/]\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[1].tooltip.text \u003d \"Dest Full (#): [bold]{valueY}[/]\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[2].tooltip.text \u003d \"Dest Jam (#): [bold]{valueY}[/]\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[3].tooltip.text \u003d \"Dest Disabled (#): [bold]{valueY}[/]\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[4].tooltip.text \u003d \"Dest Fault (#): [bold]{valueY}[/]\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[5].tooltip.text \u003d \"Divert Fail (#): [bold]{valueY}[/]\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[6].tooltip.text \u003d \"Lost (#): [bold]{valueY}[/]\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[7].tooltip.text \u003d \"Unsafe (#): [bold]{valueY}[/]\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[8].tooltip.text \u003d \"Dim Err (#): [bold]{valueY}[/]\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[9].tooltip.text \u003d \"Gap Err (#): [bold]{valueY}[/]\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[10].tooltip.text \u003d \"Unknown (#): [bold]{valueY}[/]\"\t\t\n\t\t\tself.getSibling(\"Hourly Lane\").props.yAxes[0].value.range.max \u003d \"\"\n\t\telif self.parent.parent.parent.getChild(\"Aggregation_Mode\").getChild(\"Dropdown_Aggregation_mode\").props.value \u003d\u003d \"Percentage\":\n\t\t\tpath \u003d \"Statistics/Hourly Lane Percent\"\n\t\t\theaders \u003d [\"Start Timestamp\",\"Hour\",\"Total (%)\",\"Diverted (%)\",\"Dest Full (%)\",\"Dest Jam (%)\",\"Dest Disabled (%)\",\"Dest Fault (%)\",\"Divert Fail (%)\",\"Lost (%)\",\"Unsafe (%)\",\"Dim Err (%)\",\"Gap Err (%)\",\"Unknown (%)\"]\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[0].tooltip.text \u003d \"Diverted (%): [bold]{valueY}[/]%\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[1].tooltip.text \u003d \"Dest Full (%): [bold]{valueY}[/]%\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[2].tooltip.text \u003d \"Dest Jam (%): [bold]{valueY}[/]%\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[3].tooltip.text \u003d \"Dest Disabled (%): [bold]{valueY}[/]%\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[4].tooltip.text \u003d \"Dest Fault (%): [bold]{valueY}[/]%\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[5].tooltip.text \u003d \"Divert Fail (%): [bold]{valueY}[/]%\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[6].tooltip.text \u003d \"Lost (%): [bold]{valueY}[/]%\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[7].tooltip.text \u003d \"Unsafe (%): [bold]{valueY}[/]%\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[8].tooltip.text \u003d \"Dim Err (%): [bold]{valueY}[/]%\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[9].tooltip.text \u003d \"Gap Err (%): [bold]{valueY}[/]%\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[10].tooltip.text \u003d \"Unknown (%): [bold]{valueY}[/]%\"\t\t\n\t\t\tself.getSibling(\"Hourly Lane\").props.yAxes[0].value.range.max \u003d 100\n\t\telse:\n\t\t\tpath \u003d \"Statistics/Hourly Lane Rate\"\n\t\t\theaders \u003d [\"Start Timestamp\",\"Hour\",\"Total (pph)\",\"Diverted (pph)\",\"Dest Full (pph)\",\"Dest Jam (pph)\",\"Dest Disabled (pph)\",\"Dest Fault (pph)\",\"Divert Fail (pph)\",\"Lost (pph)\",\"Unsafe (pph)\",\"Dim Err (pph)\",\"Gap Err (pph)\",\"Unknown (pph)\"]\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[0].tooltip.text \u003d \"Diverted (pph): [bold]{valueY}[/] pph\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[1].tooltip.text \u003d \"Dest Full (pph): [bold]{valueY}[/] pph\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[2].tooltip.text \u003d \"Dest Jam (pph): [bold]{valueY}[/] pph\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[3].tooltip.text \u003d \"Dest Disabled (pph): [bold]{valueY}[/] pph\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[4].tooltip.text \u003d \"Dest Fault (pph): [bold]{valueY}[/] pph\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[5].tooltip.text \u003d \"Divert Fail (pph): [bold]{valueY}[/] pph\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[6].tooltip.text \u003d \"Lost (pph): [bold]{valueY}[/] pph\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[7].tooltip.text \u003d \"Unsafe (pph): [bold]{valueY}[/] pph\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[8].tooltip.text \u003d \"Dim Err (pph): [bold]{valueY}[/] pph\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[9].tooltip.text \u003d \"Gap Err (pph): [bold]{valueY}[/] pph\"\n\t\t\tself.getSibling(\"Hourly Lane\").props.series[10].tooltip.text \u003d \"Unknown (pph): [bold]{valueY}[/] pph\"\t\n\t\t\tself.getSibling(\"Hourly Lane\").props.yAxes[0].value.range.max \u003d \"\"\n\t\t\t\n\t\tparams \u003d {\"starttime\":self.parent.parent.parent.getChild(\"Period_not_Global_0\").custom.StartDate,\"endtime\":self.parent.parent.parent.getChild(\"Period_not_Global_0\").custom.EndDate,\"lane\":self.parent.parent.parent.getChild(\"Lane Drop Down\").getChild(\"Lane\").props.value}\t\n\t\t\n\t\tdata \u003d system.dataset.toPyDataSet(system.db.runNamedQuery(path,params))\n\t\t\n\t\tfor row in data:\t\n\t\t\tdict \u003d {}\n\t\t\tdict[\u0027Hour\u0027] \u003d \trow[\u0027Hour\u0027]\n\t\t\tdict[\u0027Diverted\u0027] \u003d row[\u0027Diverted\u0027]\n\t\t\tdict[\u0027DestinationFull\u0027] \u003d row[\u0027DestinationFull\u0027]\n\t\t\tdict[\u0027DestinationJam\u0027] \u003d row[\u0027DestinationJam\u0027]\n\t\t\tdict[\u0027DestinationDisabled\u0027] \u003d row[\u0027DestinationDisabled\u0027]\n\t\t\tdict[\u0027DestinationFault\u0027] \u003d row[\u0027DestinationFault\u0027]\n\t\t\tdict[\u0027DivertFail\u0027] \u003d row[\u0027DivertFail\u0027]\n\t\t\tdict[\u0027Lost\u0027] \u003d row[\u0027Lost\u0027]\n\t\t\tdict[\u0027Unsafe\u0027] \u003d row[\u0027Unsafe\u0027]\n\t\t\tdict[\u0027DimError\u0027] \u003d row[\u0027DimError\u0027]\n\t\t\tdict[\u0027GapError\u0027] \u003d row[\u0027GapError\u0027]\n\t\t\tdict[\u0027Unknown\u0027] \u003d row[\u0027Unknown\u0027]\n\t\t\tgraph.append(dict)\n\t\t\n\t\tself.getSibling(\"Hourly Lane\").props.dataSources.example \u003d graph\n\t\tself.props.data \u003d system.dataset.toDataSet(headers,data)\n" } }, "custom.time": { @@ -9489,14 +9626,77 @@ "$": [ "ds", 192, - 1747403902267 + 1747664567761 ], "$columns": [ { - "data": [ - "Database connection failed: \u0027com.inductiveautomation.ignition.common.BasicDataset\u0027 object is not iterable" - ], - "name": "Error", + "data": [], + "name": "Start Timestamp", + "type": "String" + }, + { + "data": [], + "name": "Hour", + "type": "String" + }, + { + "data": [], + "name": "Total (#)", + "type": "String" + }, + { + "data": [], + "name": "Diverted (#)", + "type": "String" + }, + { + "data": [], + "name": "Dest Full (#)", + "type": "String" + }, + { + "data": [], + "name": "Dest Jam (#)", + "type": "String" + }, + { + "data": [], + "name": "Dest Disabled (#)", + "type": "String" + }, + { + "data": [], + "name": "Dest Fault (#)", + "type": "String" + }, + { + "data": [], + "name": "Divert Fail (#)", + "type": "String" + }, + { + "data": [], + "name": "Lost (#)", + "type": "String" + }, + { + "data": [], + "name": "Unsafe (#)", + "type": "String" + }, + { + "data": [], + "name": "Dim Err (#)", + "type": "String" + }, + { + "data": [], + "name": "Gap Err (#)", + "type": "String" + }, + { + "data": [], + "name": "Unknown (#)", "type": "String" } ] @@ -24759,7 +24959,7 @@ "$": [ "ds", 192, - 1747403052050 + 1747664538963 ], "$columns": [ { @@ -27532,7 +27732,7 @@ "$": [ "ds", 192, - 1747403052050 + 1747664538963 ], "$columns": [ { @@ -31096,7 +31296,7 @@ }, "props": { "dismissOnSelect": false, - "formattedValue": "May 16, 2025 4:58 PM", + "formattedValue": "May 19, 2025 5:22 PM", "formattedValues": { "date": "Mar 26, 2021", "datetime": "Mar 26, 2021 12:00 AM", @@ -31106,9 +31306,9 @@ "$": [ "ts", 192, - 1747403903262 + 1747664567742 ], - "$ts": 1747400303000 + "$ts": 1747660967000 } }, "type": "ia.input.date-time-input" @@ -31256,7 +31456,7 @@ }, "props": { "dismissOnSelect": false, - "formattedValue": "May 16, 2025 5:58 PM", + "formattedValue": "May 19, 2025 6:22 PM", "formattedValues": { "date": "Mar 29, 2021", "datetime": "Mar 29, 2021 1:37 PM", @@ -31266,9 +31466,9 @@ "$": [ "ts", 192, - 1747403903257 + 1747664567742 ], - "$ts": 1747403903000 + "$ts": 1747664567000 } }, "type": "ia.input.date-time-input"