Reputation: 1
I’m working on a configuration tool that takes an I/O spreadsheet and rearranges the data into a specific format. For example, if the spreadsheet specifies a data type like DOL, the tool identifies it and retrieves the corresponding function block from the PLC library.
To clarify, all the function blocks are already created in the library. The tool’s job is to:
Grab the required function blocks from the library. Place them on the ladder logic grid. Populate their inputs and outputs based on the I/O list from the spreadsheet. Modify or generate the XML file needed to import this configuration into the PLC program.
Since the XML file exported from PLCnext Engineer is very large, I’m exploring the most efficient way to modify specific sections of it. If anyone has ideas or suggestions on how to streamline this process, I’d greatly appreciate your input. Thank you!
from lxml import etree
import os
# Function to modify the XML with the given number of DOL blocks
def adjust_dol_blocks(xml_file, num_blocks):
try:
tree = etree.parse(xml_file)
except etree.XMLSyntaxError as e:
print(f"Error parsing XML file: {e}")
return
root = tree.getroot()
# Define namespaces, including the xsi namespace
namespace = {
"ns": "www.iec.ch/public/TC65SC65BWG7TF10",
"xsi": "http://www.w3.org/2001/XMLSchema-instance"
}
# Find the BodyContent section with xsi:type="LD"
body_content = root.xpath(".//ns:BodyContent[@xsi:type='LD']", namespaces=namespace)
if not body_content:
print("Error: Could not find the BodyContent element with xsi:type='LD'.")
return
body_content = body_content[0] # Take the first match if multiple
# Find all <Rung> elements within the BodyContent
rungs = body_content.xpath(".//ns:Rung", namespaces=namespace)
# Current number of DOL blocks in the XML
current_blocks = len(rungs)
if current_blocks < num_blocks:
# Add new DOL blocks if needed
for i in range(current_blocks, num_blocks):
new_rung = create_new_rung(i, namespace)
body_content.append(new_rung)
elif current_blocks > num_blocks:
# Remove excess DOL blocks if needed
for i in range(current_blocks - 1, num_blocks - 1, -1):
body_content.remove(rungs[i])
# Save the modified XML back to the file
new_file_path = "modified_" + os.path.basename(xml_file)
tree.write(new_file_path, pretty_print=True, xml_declaration=True, encoding="utf-8")
print(f"Modified XML file saved as {new_file_path}")
def create_new_rung(index, namespace):
# This function creates a new Rung with a unique DOL block
rung = etree.Element("{www.iec.ch/public/TC65SC65BWG7TF10}Rung", evaluationOrder=str(index + 1))
rel_position = etree.SubElement(rung, "{www.iec.ch/public/TC65SC65BWG7TF10}RelPosition", x="26", y=str(4 + index * 32)) # Adjust Y for spacing
# Add a new FbdObject (DOL block)
fbd_object = etree.SubElement(rung, "{www.iec.ch/public/TC65SC65BWG7TF10}FbdObject",
xsi_type="Block", globalId=f"ID_NewProgram_Code_{index + 1}",
typeName="DOL", instanceName=f"DOL{index + 1}")
# Adding the required internal structure (like AddData)
add_data = etree.SubElement(fbd_object, "{www.iec.ch/public/TC65SC65BWG7TF10}AddData")
data = etree.SubElement(add_data, "{www.iec.ch/public/TC65SC65BWG7TF10}Data", name="objectInformation", handleUnknown="preserve")
return rung
def main():
# Prompt for file path and validate it
xml_file = input("Enter the full file path of the XML file: ").strip()
if not os.path.isfile(xml_file):
print(f"Error: The file '{xml_file}' does not exist. Please check the path and try again.")
return
# Prompt for the number of DOL blocks
try:
num_blocks = int(input("Enter the desired number of DOL blocks: ").strip())
except ValueError:
print("Error: Please enter a valid integer for the number of blocks.")
return
# Call the function to adjust the DOL blocks
adjust_dol_blocks(xml_file, num_blocks)
# Run the main function
if __name__ == "__main__":
main()
This is my code currently which takes inserted XML file and ask user for numbers of blocks. But ultimately i want it to just automatically does it. and purely base on how many for example DOL tags there are in the csv file.
Upvotes: 0
Views: 17