206 lines
8.5 KiB
Python
206 lines
8.5 KiB
Python
"""
|
|
!!! CHANGE THE INPUT_FILE VARIABLE TO THE PATH OF THE TEXT FILE! LINE 17 !!!
|
|
|
|
IF YOU WANT TO RUN THIS SCRIPT, YOU NEED TO HAVE A TXT FILE WITH THE FOLLOWING FORMAT:
|
|
DPM_NAME
|
|
DEVICE_NAME1 DEVICE_IP1
|
|
DEVICE_NAME2 DEVICE_IP2
|
|
...
|
|
DEVICE_NAMEN DEVICE_IPN
|
|
DPM_NAMEN
|
|
...
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import shutil
|
|
|
|
# Get the directory where this script is located
|
|
script_dir = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
input_file = os.path.join(script_dir, "device_mapping.txt")
|
|
mcm_folder_name = "MCM"
|
|
|
|
def generate_config(num_vfds, num_fios, device_list, dpm_label):
|
|
if num_vfds + num_fios > 24:
|
|
raise ValueError("Error: Total number of VFDs and FIOs/SIOs cannot exceed 24 slots.")
|
|
if len(device_list) != num_vfds + num_fios:
|
|
raise ValueError(f"Error: Expected {num_vfds + num_fios} device names, but got {len(device_list)}.")
|
|
|
|
# Predefined positions and labels for devices (up to 24)
|
|
positions = [
|
|
{"x": 0.0232, "y": 0.4991}, {"x": 0.0230, "y": 0.6677}, {"x": 0.0216, "y": 0.8333}, # 3
|
|
{"x": 0.0229, "y": 0.3333}, {"x": 0.0229, "y": 0.1667}, {"x": 0.0244, "y": 0.0000}, # 6
|
|
{"x": 0.5000, "y": 0.0000}, {"x": 0.6250, "y": 0.0000}, {"x": 0.7500, "y": 0.0000}, # 9
|
|
{"x": 0.3750, "y": 0.0000}, {"x": 0.2516, "y": 0.0019}, {"x": 0.1245, "y": 0.0000}, # 12
|
|
{"x": 0.8509, "y": 0.3332}, {"x": 0.8514, "y": 0.1667}, {"x": 0.8528, "y": 0.0000}, # 15
|
|
{"x": 0.8509, "y": 0.4988}, {"x": 0.8501, "y": 0.6639}, {"x": 0.8515, "y": 0.8329}, # 18
|
|
{"x": 0.3740, "y": 0.8324}, {"x": 0.2481, "y": 0.8324}, {"x": 0.1222, "y": 0.8333}, # 21
|
|
{"x": 0.5026, "y": 0.8314}, {"x": 0.6245, "y": 0.8314}, {"x": 0.7536, "y": 0.8351} # 24
|
|
]
|
|
|
|
label_positions = [
|
|
{"x": 0.0094, "y": 0.5394}, {"x": 0.0068, "y": 0.7315}, {"x": 0.0068, "y": 0.8981}, # 3
|
|
{"x": 0.0068, "y": 0.3986}, {"x": 0.0068, "y": 0.2324}, {"x": 0.0068, "y": 0.0653}, # 6
|
|
{"x": 0.5117, "y": 0.1662}, {"x": 0.6312, "y": 0.1664}, {"x": 0.7500, "y": 0.1664}, # 9
|
|
{"x": 0.3864, "y": 0.1664}, {"x": 0.3150, "y": 0.1682}, {"x": 0.2072, "y": 0.1646}, # 12
|
|
{"x": 0.9470, "y": 0.3943}, {"x": 0.9470, "y": 0.2276}, {"x": 0.9470, "y": 0.0619}, # 15
|
|
{"x": 0.9470, "y": 0.5610}, {"x": 0.9470, "y": 0.7257}, {"x": 0.9470, "y": 0.8927}, # 18
|
|
{"x": 0.4587, "y": 0.8896}, {"x": 0.3311, "y": 0.8887}, {"x": 0.2071, "y": 0.8886}, # 21
|
|
{"x": 0.5887, "y": 0.8886}, {"x": 0.7106, "y": 0.8886}, {"x": 0.8344, "y": 0.9247} # 24
|
|
]
|
|
|
|
total_devices = num_vfds + num_fios
|
|
tag_props = [f"TAG{i}" for i in range(total_devices)]
|
|
con_lines_visible = [True] * total_devices + [False] * (24 - total_devices)
|
|
|
|
# Generate propConfig for con_lines bindings
|
|
prop_config = {}
|
|
for i in range(total_devices):
|
|
prop_config[f"props.params.con_lines[{i}]"] = {
|
|
"binding": {
|
|
"config": {
|
|
"fallbackDelay": 2.5,
|
|
"mode": "indirect",
|
|
"references": {"0": f"{{view.params.tagProps[{i}]}}", "fc": "{session.custom.fc}"},
|
|
"tagPath": "[{fc}_SCADA_TAG_PROVIDER]{0}/Alarms/Communication_Faulted"
|
|
},
|
|
"transforms": [
|
|
{"expression": "coalesce({value},{view.params.forceFaultStatus},false)", "type": "expression"},
|
|
{"fallback": False, "inputType": "scalar", "mappings": [{"input": False, "output": True}], "outputType": "scalar", "type": "map"}
|
|
],
|
|
"type": "tag"
|
|
}
|
|
}
|
|
|
|
# Base configuration
|
|
config = {
|
|
"custom": {},
|
|
"params": {"tagProps": tag_props},
|
|
"props": {"defaultSize": {"height": 1080, "width": 1920}},
|
|
"root": {
|
|
"children": [],
|
|
"meta": {"name": "root"},
|
|
"position": {"x": 0.6348, "y": -0.1546},
|
|
"props": {"mode": "percent"},
|
|
"type": "ia.container.coord"
|
|
}
|
|
}
|
|
|
|
# Add DPM component
|
|
config["root"]["children"].append({
|
|
"meta": {"name": "DPM"},
|
|
"position": {"x": 0, "y": 0, "height": 1, "width": 1},
|
|
"propConfig": prop_config,
|
|
"props": {
|
|
"params": {"con_lines": [False] * 24, "con_lines_visible": con_lines_visible, "in": False, "out": False},
|
|
"path": "Windows/Tabs/Enternet Windows/Components/DPM_TO_HUB"
|
|
},
|
|
"type": "ia.display.view"
|
|
})
|
|
|
|
# Process all devices
|
|
for i, device_data in enumerate(device_list):
|
|
name, ip = device_data.split()
|
|
is_vfd = '_VFD' in name or '_EX' in name
|
|
component_name = name.replace("_VFD1", "").replace("_EX1", "") if is_vfd else name
|
|
|
|
# Adjust X position for FIO/SIO at positions 13-18
|
|
component_x = positions[i]["x"]
|
|
label_x = label_positions[i]["x"]
|
|
if not is_vfd and 12 <= i <= 17:
|
|
component_x -= 0.012
|
|
label_x -= 0.012
|
|
|
|
# Add device component
|
|
config["root"]["children"].append({
|
|
"meta": {"name": component_name},
|
|
"position": {"height": 0.1667, "width": 0.125, "x": component_x, "y": positions[i]["y"]},
|
|
"props": {"path": f"Windows/Tabs/Enternet Windows/Components/{'APF' if is_vfd else 'FIO_SIO'}"},
|
|
"type": "ia.display.view"
|
|
})
|
|
|
|
# Add device label
|
|
config["root"]["children"].append({
|
|
"meta": {"name": f"{component_name}_label"},
|
|
"position": {"height": 0.0358, "width": 0.0547 if is_vfd else 0.0427, "x": label_x, "y": label_positions[i]["y"]},
|
|
"props": {"text": f"{name} {ip}", "textStyle": {"fontSize": "1vmin", "key": "value"}},
|
|
"type": "ia.display.label"
|
|
})
|
|
|
|
# Add DPM label
|
|
config["root"]["children"].append({
|
|
"meta": {"name": "DPM_label"},
|
|
"position": {"height": 0.0694, "width": 0.101, "x": 0.5831, "y": 0.6342},
|
|
"props": {"text": dpm_label, "textStyle": {"fontSize": "2vmin"}},
|
|
"type": "ia.display.label"
|
|
})
|
|
|
|
return config
|
|
|
|
def parse_dpm_data(file_path):
|
|
dpms = {}
|
|
current_dpm = None
|
|
with open(file_path, 'r') as f:
|
|
for line in f:
|
|
line = line.strip()
|
|
if not line:
|
|
continue
|
|
if not ('\t' in line and len(line.split('\t')) == 2) and not (' ' in line and len(line.split(' ')) == 2):
|
|
current_dpm = line
|
|
dpms[current_dpm] = []
|
|
elif current_dpm:
|
|
parts = line.split('\t') if '\t' in line else line.split(' ')
|
|
dpms[current_dpm].append((parts[0].strip(), parts[1].strip()))
|
|
return dpms
|
|
|
|
def copy_files_to_dpm_folder(dpm_folder):
|
|
script_dir = os.path.dirname(os.path.abspath(__file__))
|
|
for file_name in ["resource.json", "thumbnail.png"]:
|
|
source = os.path.join(script_dir, file_name)
|
|
if os.path.exists(source):
|
|
shutil.copy2(source, os.path.join(dpm_folder, file_name))
|
|
|
|
def create_dpm_folders(dpms, mcm_folder):
|
|
os.makedirs(mcm_folder, exist_ok=True)
|
|
for dpm_name, devices in dpms.items():
|
|
print(f"Processing {dpm_name} with {len(devices)} devices...")
|
|
dpm_folder = os.path.join(mcm_folder, dpm_name)
|
|
os.makedirs(dpm_folder, exist_ok=True)
|
|
|
|
try:
|
|
# Count device types and create config
|
|
num_vfds = sum(1 for name, _ in devices if '_VFD' in name or '_EX' in name)
|
|
num_fios = len(devices) - num_vfds
|
|
device_list = [f"{name} {ip}" for name, ip in devices]
|
|
|
|
config = generate_config(num_vfds, num_fios, device_list, dpm_name)
|
|
|
|
# Save view.json and copy files
|
|
with open(os.path.join(dpm_folder, "view.json"), 'w') as f:
|
|
json.dump(config, f, indent=2)
|
|
copy_files_to_dpm_folder(dpm_folder)
|
|
|
|
except Exception as e:
|
|
print(f"Error processing {dpm_name}: {e}")
|
|
|
|
def main():
|
|
try:
|
|
if not input_file or not os.path.exists(input_file):
|
|
print(f"Error: File '{input_file}' not found.")
|
|
return
|
|
|
|
dpms = parse_dpm_data(input_file)
|
|
if not dpms:
|
|
print("No DPM data found in the input file.")
|
|
return
|
|
|
|
print(f"Found {len(dpms)} DPMs. Creating MCM folder '{mcm_folder_name}'...")
|
|
create_dpm_folders(dpms, mcm_folder_name)
|
|
print("Completed successfully, check the MCM folder!")
|
|
|
|
except Exception as e:
|
|
print(f"An error occurred: {str(e)}")
|
|
|
|
if __name__ == "__main__":
|
|
main() |