Blog

Automating Alarm Generation in Rockwell

Overview:

Rockwell’s does not natively give a method to export controller tags from the PLC and import the tags as alarms to FactoryTalk. This can be problematic as some projects can contain thousands of alarms with mostly repetitive information. This article will serve as a guide on how to automate the creation of trigger tags and alarm messages.

Prerequisites:

  • Errors should be mapped into a user-defined variable that contains symbolic and representative names for the error
    • Usually, each error data type corresponds with a particular type of device or process. (For example, the same alarm UDT can be used for all analog inputs)
  • All error tags should have a prefix to isolate them as error tags
  • All errors should be of the Boolean type
    • An example of an error-tag would be “ERROR_Valve_01.NoHomeFeedback”
  • You will need to install a Python test environment to run the script
    • PyCharm
    • Spyder – Used in this example
    • Visual Studio

Exporting Error Tags from Logix Designer:

Logix Designer does give the option to export controller tags as a comma-separate-value file, but this file will not include the user-defined variable definitions. The best way to create an export of all the error tags with the type definitions is to first open the “Controller Tags” window, expand all error tags, select them, and copy them into a text document.

Steps:

  1. Open Controller Tags Window
  2. Copy alarm variables
  3. Paste into an empty text file

You should now be able to save this text file as something relevant. In this example, the file name will be, “ErrorTags.txt”.

Formatting the data with Python:

FactoryTalk alarms can be imported using a specific XML format. The following script will show how to open the text file, parse the date, create string messages, and write to an XML file.

The function below will perform the following tasks in order:

  1. Open the text file
  2. Map the text file to a matrix of data
  3. Map the first index of the data into an array with only tag names
  4. Remove the header tags of the UDT instance
				
					
def parse_text_to_matrix(file_path):
    matrix_temp = []                                # initialize matrix
    matrix = []                                     # initialize matrix
    with open(file_path, 'r') as file:              # Open the file
        for line in file:
            row = line.strip().split()              # Split into array elements
            matrix_temp.append(row)                 # Write to temp matrix
    for i in range(len(matrix_temp)):               # Isolate relevant data
        if '.' in matrix_temp[i][0]:                # Remove header tags
            matrix.append(matrix_temp[i][0])
    return matrix                                   # Output final arrray
				
			

Next, we will call the function to format the alarm messages using the tag names. The function will iterate through the alarm messages and format the message. This function block may need to be changed to fit your specific formatting needs.

The code snippet will perform the following transformation:

ERROR_Control_Valve_Tank_1_HPNV01.InvalidFeedback –> Control Valve Tank 1 – HPNV01 – Invalid Feedback

				
					
def FormatString(input_TagArray):
    message_array = []
    for i in range(len(tags_array)):
        sMessage = input_TagArray[i].replace('ERROR_', '')      # Remove Error_
        sMessage = sMessage.replace('_', ' ')                   # Replace underscores with spaces
        sMessage = sMessage.replace('.', ' - ')                 # Replace periods with dashes
        sMessage = re.sub(r'(?<!^)(?=[A-Z])', ' ', sMessage)    # Add spaces where there is a case change
        sMessage = sMessage.replace('  ', ' ')                  # Remove double spaces
        sMessage = sMessage.replace('V F D', 'VFD')             # correct the term VFD
        sMessage = sMessage.replace('M F', '- MF.')             # correct the term MF
        sMessage = sMessage.replace('P T', '- PT.')             # Correct the term PT
        sMessage = sMessage.replace('H P N V', '- HPNV.')       # Correct the term HPNV
        sMessage = sMessage.replace('Pump0', '- Pump.0')        # Correct the term Pump
        message_array.append(sMessage)
    return message_array
				
			

Next, we will create a function to create our XML file with our trigger tags and our error messages. The header information can be found by exporting an empty alarm configuration from FactoryTalk.

				
					
def WriteOutput(tags_array, message_array):
    with open('output.xml', 'w') as file:
        # Print the header
        file.write('\n')
        file.write('\n')
        file.write('    \n')
        
        # Print Triggers
        file.write('        \n')
        for i in range(len(tags_array)):
            file.write('                        \n')
            
        file.write('		\n')
        
        # Print Messages
        file.write('        \n')
        for i in range(len(tags_array)):
            file.write('                \n')
        file.write('        \n')
        
        # Closer
        file.write('    \n')
        file.write('\n')
				
			

Finally, we can call our functions together and declare the name of our input file.

				
					file_path = 'ErrorTags.txt'                         # Input File Name
tags_array = parse_text_to_matrix(file_path)        # Create array of tag names
message_array = FormatString(tags_array)            # Create array of alarm messages
WriteOutput(tags_array, message_array)              # Generate the final XML file
				
			

Importing to Factory Talk:

From the script above we should now have a file called, “output.XML” that we can import into FactoryTalk. Below are instructions on how to import this file.

  1. Open your FactoyTalk ME project
  2. Right-click on Alarm Setup (ProjectName/ProjectName/ProjectName/Alarms/Alarm Setup)
  3. Select “Import and Export”
  4. Complete the import wizard

After completing the setup wizard, Factory Talk will open Notepad and display a message to indicate whether the import was successful or not. See the section labeled, “Troubleshooting common issues” if the import fails.

Troubleshooting Common issues:

Messages do not look as expected

The message text may take a few tries to get right. A common tool is to add a space whenever the case changes in a tag name. (for example, LowLowAlarm à Low Low Alarm) This can be helpful but may also create some problems with project-specific acronyms. The code attached to this article should give a few examples of how to create exceptions to these rules. An example of this can be seen on line 30 where V F D is formatted back into VFD.

Another common issue is creating double spaces while formatting the text. An easy solution for this is to use the replace method as seen in line 29. This line will check every message and replace any double space with a single space.

FactoryTalk failed to import the XML

The formatting of the XML file may vary slightly between FactoryTalk versions and projects. An easy method to ensure that the XML will match is to create a few alarms manually and then export the alarm configuration. With this, you can compare the header information between the file you created and the file that was generated by the software and adjust accordingly.

Problems installing Python:

Although Python can be installed independently directly from the command prompt with the command “python”. It is generally preferred to install an entire Python environment. An environment such as Spyder with Anacona will give you access to features such as:

  • a variable explorer
  • A kernel interface
  • Program error descriptions

Instructions for installing and general use can be found at Spyder | Anaconda.org

Closing:

Although creating and using a tool like this may not be practical for every project, the time invested in troubleshooting the script can be negligible should the amount of needed error messages grow long. The main advantage of using an iterative script such as this rather than creating the alarms manually is the ability to quickly change the verbiage/wording across all alarms to a particular user-defined data type. Traditionally, the end user does not get much input into the alarm text due to the amount of time required to make modifications to large systems. With the use of scripting, we can generate and modify alarm texts with little effort.

Full Code:

				
					# -*- coding: utf-8 -*-
"""
Created on Wed Nov  6 13:41:40 2024

@author: JerimaeWilliams
"""

import re

def parse_text_to_matrix(file_path):
    matrix_temp = []                                # initialize matrix
    matrix = []                                     # initialize matrix
    with open(file_path, 'r') as file:              # Open the file
        for line in file:
            row = line.strip().split()              # Split into array elements
            matrix_temp.append(row)                 # Write to temp matrix
    for i in range(len(matrix_temp)):               # Isolate relevant data
        if '.' in matrix_temp[i][0]:                # Remove header tags
            matrix.append(matrix_temp[i][0])
    return matrix                                   # Output final arrray

def FormatString(input_TagArray):
    message_array = []
    for i in range(len(tags_array)):
        sMessage = input_TagArray[i].replace('ERROR_', '')      # Remove Error_
        sMessage = sMessage.replace('_', ' ')                   # Replace underscores with spaces
        sMessage = sMessage.replace('.', ' - ')                 # Replace periods with dashes
        sMessage = re.sub(r'(?<!^)(?=[A-Z])', ' ', sMessage)    # Add spaces where there is a case change
        sMessage = sMessage.replace('  ', ' ')                  # Remove double spaces
        sMessage = sMessage.replace('V F D', 'VFD')             # correct the term VFD
        sMessage = sMessage.replace('M F', '- MF.')             # correct the term MF
        sMessage = sMessage.replace('P T', '- PT.')             # Correct the term PT
        sMessage = sMessage.replace('H P N V', '- HPNV.')       # Correct the term HPNV
        sMessage = sMessage.replace('Pump0', '- Pump.0')        # Correct the term Pump
        message_array.append(sMessage)
    return message_array

def WriteOutput(tags_array, message_array):
    with open('output.xml', 'w') as file:
        # Print the header
        file.write('\n')
        file.write('\n')
        file.write('    \n')
        
        # Print Triggers
        file.write('        \n')
        for i in range(len(tags_array)):
            file.write('                        \n')
            
        file.write('		\n')
        
        # Print Messages
        file.write('        \n')
        for i in range(len(tags_array)):
            file.write('                \n')
        file.write('        \n')
        
        # Closer
        file.write('    \n')
        file.write('\n')

# Call functions
file_path = 'ErrorTags.txt'                         # Input File Name
tags_array = parse_text_to_matrix(file_path)        # Create array of tag names
message_array = FormatString(tags_array)            # Create array of alarm messages
WriteOutput(tags_array, message_array)              # Generate the final XML file
				
			

Share this post

Leave A Comment

Let's work together to solve your automation problem

Call 480-900-2170