2025-07-22 12:44:17 +04:00

374 lines
20 KiB
Python

import json
def get_dpm_positions(dpm_count):
"""
Return a list of position dictionaries for DPM_DEVICE and DPM_label entries.
Uses positions from fourth view.json for 1-4 DPMs, third view.json for 5-6 DPMs,
second view.json for 7-8 DPMs, first view.json (updated) for 9-11 DPMs, and
first view.json with DPM12 and placeholders for 12+. For 7 DPMs, skips the first
position and uses positions 2-8 from second view.json.
"""
# Positions from fourth view.json (for 1-4 DPMs)
device_positions_4 = [
{"x": 0.5, "y": 0.5, "width": 0.5, "height": 0.5}, # DPM1
{"x": 0.5, "y": 0, "width": 0.5, "height": 0.5}, # DPM2
{"x": 0, "y": 0, "width": 0.5, "height": 0.5}, # DPM3
{"x": 0, "y": 0.5, "width": 0.5, "height": 0.5} # DPM4
]
label_positions_4 = [
{"x": 0.5, "y": 0.6, "width": 0.0547, "height": 0.0358}, # DPM1_label
{"x": 0.5, "y": 0.1, "width": 0.0547, "height": 0.0358}, # DPM2_label
{"x": 0.01, "y": 0.1, "width": 0.0547, "height": 0.0358}, # DPM3_label
{"x": 0.01, "y": 0.6, "width": 0.0547, "height": 0.0358} # DPM4_label
]
# Positions from third view.json (for 5-6 DPMs)
device_positions_3 = [
{"x": 0.6666, "y": 0.5, "width": 0.3333, "height": 0.5}, # DPM1
{"x": 0.6666, "y": 0, "width": 0.3333, "height": 0.5}, # DPM2
{"x": 0.3333, "y": 0, "width": 0.3333, "height": 0.5}, # DPM3
{"x": 0, "y": 0, "width": 0.3333, "height": 0.5}, # DPM4
{"x": 0, "y": 0.5, "width": 0.3333, "height": 0.5}, # DPM5
{"x": 0.3333, "y": 0.5, "width": 0.3333, "height": 0.5} # DPM6
]
label_positions_3 = [
{"x": 0.65, "y": 0.6, "width": 0.0547, "height": 0.0358}, # DPM1_label
{"x": 0.65, "y": 0.1, "width": 0.0547, "height": 0.0358}, # DPM2_label
{"x": 0.32, "y": 0.1, "width": 0.0547, "height": 0.0358}, # DPM3_label
{"x": 0.005, "y": 0.1, "width": 0.0547, "height": 0.0358}, # DPM4_label
{"x": 0.005, "y": 0.6, "width": 0.0547, "height": 0.0358}, # DPM5_label
{"x": 0.32, "y": 0.6, "width": 0.0547, "height": 0.0358} # DPM6_label
]
# Positions from second view.json (for 7-8 DPMs)
device_positions_2 = [
{"x": 0.6666, "y": 0.3333, "width": 0.3333, "height": 0.3333}, # DPM1
{"x": 0.6666, "y": 0, "width": 0.3333, "height": 0.3333}, # DPM2
{"x": 0.3333, "y": 0, "width": 0.3333, "height": 0.3333}, # DPM3
{"x": 0, "y": 0, "width": 0.3333, "height": 0.3333}, # DPM4
{"x": 0, "y": 0.3333, "width": 0.3333, "height": 0.3333}, # DPM5
{"x": 0, "y": 0.6666, "width": 0.3333, "height": 0.3333}, # DPM6
{"x": 0.3333, "y": 0.6666, "width": 0.3333, "height": 0.3333}, # DPM7
{"x": 0.3333, "y": 0.3333, "width": 0.3333, "height": 0.3333} # DPM8
]
label_positions_2 = [
{"x": 0.65, "y": 0.4, "width": 0.0547, "height": 0.0358}, # DPM1_label
{"x": 0.65, "y": 0.07, "width": 0.0547, "height": 0.0358}, # DPM2_label
{"x": 0.32, "y": 0.07, "width": 0.0547, "height": 0.0358}, # DPM3_label
{"x": 0.065, "y": 0.3, "width": 0.0547, "height": 0.0358}, # DPM4_label
{"x": 0.005, "y": 0.4, "width": 0.0547, "height": 0.0358}, # DPM5_label
{"x": 0.005, "y": 0.75, "width": 0.0547, "height": 0.0358}, # DPM6_label
{"x": 0.32, "y": 0.75, "width": 0.0547, "height": 0.0358}, # DPM7_label
{"x": 0.32, "y": 0.4, "width": 0.0547, "height": 0.0358} # DPM8_label
]
# Positions from first view.json (for 9-11 DPMs, updated with new DPM10-DPM12)
device_positions_1 = [
{"x": 0.75, "y": 0.3333, "width": 0.25, "height": 0.3333}, # DPM1
{"x": 0.75, "y": 0, "width": 0.25, "height": 0.3333}, # DPM2
{"x": 0.5, "y": 0, "width": 0.25, "height": 0.3333}, # DPM3
{"x": 0.5, "y": 0.3333, "width": 0.25, "height": 0.3333}, # DPM4
{"x": 0.2503, "y": 0.3333, "width": 0.25, "height": 0.3333},# DPM5
{"x": 0.2503, "y": 0, "width": 0.25, "height": 0.3333}, # DPM6
{"x": 0, "y": 0, "width": 0.25, "height": 0.3333}, # DPM7
{"x": 0, "y": 0.3333, "width": 0.25, "height": 0.3333}, # DPM8
{"x": 0, "y": 0.6667, "width": 0.25, "height": 0.3333}, # DPM9
{"x": 0.2503, "y": 0.6667, "width": 0.25, "height": 0.3333},# DPM10
{"x": 0.5, "y": 0.6667, "width": 0.25, "height": 0.3333}, # DPM11
{"x": 0.75, "y": 0.6667, "width": 0.25, "height": 0.3333} # DPM12
]
label_positions_1 = [
{"x": 0.7302, "y": 0.4125, "width": 0.0547, "height": 0.0358}, # DPM1_label
{"x": 0.7302, "y": 0.0747, "width": 0.0547, "height": 0.0358}, # DPM2_label
{"x": 0.4755, "y": 0.0748, "width": 0.0547, "height": 0.0358}, # DPM3_label
{"x": 0.4726, "y": 0.4125, "width": 0.0547, "height": 0.0358}, # DPM4_label
{"x": 0.2281, "y": 0.4125, "width": 0.0547, "height": 0.0358}, # DPM5_label
{"x": 0.2284, "y": 0.0744, "width": 0.0547, "height": 0.0358}, # DPM6_label
{"x": 0.0484, "y": 0.278, "width": 0.0547, "height": 0.0358}, # DPM7_label
{"x": 0.0064, "y": 0.3772, "width": 0.0547, "height": 0.0358}, # DPM8_label
{"x": 0.0062, "y": 0.7079, "width": 0.0547, "height": 0.0358}, # DPM9_label
{"x": 0.2279, "y": 0.7437, "width": 0.0547, "height": 0.0358}, # DPM10_label
{"x": 0.4755, "y": 0.7438, "width": 0.0547, "height": 0.0358}, # DPM11_label
{"x": 0.7302, "y": 0.7438, "width": 0.0547, "height": 0.0358} # DPM12_label
]
# Positions from first view.json (for 9-11 DPMs, updated with new DPM12-DPM15)
device_positions_6 = [
{"x": 0.75, "y": 0.5, "width": 0.25, "height": 0.25}, # DPM1
{"x": 0.75, "y": 0.25, "width": 0.25, "height": 0.25}, # DPM2
{"x": 0.75, "y": 0, "width": 0.25, "height": 0.25}, # DPM3
{"x": 0.5, "y": 0, "width": 0.25, "height": 0.25}, # DPM4
{"x": 0.5, "y": 0.25, "width": 0.25, "height": 0.25},# DPM5
{"x": 0.25, "y": 0.25, "width": 0.25, "height": 0.25}, # DPM6
{"x": 0.25, "y": 0, "width": 0.25, "height": 0.25}, # DPM7
{"x": 0, "y": 0, "width": 0.25, "height": 0.25}, # DPM8
{"x": 0, "y": 0.25, "width": 0.25, "height": 0.25}, # DPM9
{"x": 0, "y": 0.5, "width": 0.25, "height": 0.25},# DPM10
{"x": 0, "y": 0.75, "width": 0.25, "height": 0.25}, # DPM11
{"x": 0.25, "y": 0.75, "width": 0.25, "height": 0.25}, # DPM12
{"x": 0.25, "y": 0.5, "width": 0.25, "height": 0.25},# DPM13
{"x": 0.5, "y": 0.5, "width": 0.25, "height": 0.25}, # DPM14
{"x": 0.5, "y": 0.75, "width": 0.25, "height": 0.25} # DPM15
]
label_positions_6 = [
{"x": 0.7302, "y": 0.5421, "width": 0.0547, "height": 0.0358}, # DPM1_label
{"x": 0.7302, "y": 0.3005, "width": 0.0547, "height": 0.0358}, # DPM2_label
{"x": 0.7302, "y": 0.0744, "width": 0.0547, "height": 0.0358}, # DPM3_label
{"x": 0.4755, "y": 0.0744, "width": 0.0547, "height": 0.0358}, # DPM4_label
{"x": 0.4755, "y": 0.3005, "width": 0.0547, "height": 0.0358}, # DPM5_label
{"x": 0.2284, "y": 0.3005, "width": 0.0547, "height": 0.0358}, # DPM6_label
{"x": 0.2284, "y": 0.0744, "width": 0.0547, "height": 0.0358}, # DPM7_label
{"x": 0.0442, "y": 0.2109, "width": 0.0547, "height": 0.0358}, # DPM8_label
{"x": 0.0054, "y": 0.2855, "width": 0.0547, "height": 0.0358}, # DPM9_label
{"x": 0.0054, "y": 0.5399, "width": 0.0547, "height": 0.0358}, # DPM10_label
{"x": 0.0054, "y": 0.7863, "width": 0.0547, "height": 0.0358}, # DPM11_label
{"x": 0.2284, "y": 0.7885, "width": 0.0547, "height": 0.0358}, # DPM12_label
{"x": 0.2284, "y": 0.5421, "width": 0.0547, "height": 0.0358}, # DPM13_label
{"x": 0.4755, "y": 0.5421, "width": 0.0547, "height": 0.0358}, # DPM14_label
{"x": 0.4755, "y": 0.7885, "width": 0.0547, "height": 0.0358}, # DPM15_label
]
# Select positions based on dpm_count
if dpm_count in [1, 2, 3, 4]:
device_positions = device_positions_4[:dpm_count]
label_positions = label_positions_4[:dpm_count]
elif dpm_count in [5, 6]:
device_positions = device_positions_3[:dpm_count]
label_positions = label_positions_3[:dpm_count]
elif dpm_count == 7:
# For 7 DPMs, use positions 2-8 from second view.json
device_positions = device_positions_2[1:8]
label_positions = label_positions_2[1:8]
elif dpm_count == 8:
# For 8 DPMs, use all positions from second view.json
device_positions = device_positions_2[:8]
label_positions = label_positions_2[:8]
elif dpm_count >= 13:
# For 13-15 DPMs + 1 MCM, use device_positions_6 and label_positions_6
# MCM is always at the last position
device_positions = device_positions_6[:dpm_count]
label_positions = label_positions_6[:dpm_count]
elif dpm_count == 13:
# For 12 DPMs + 1 MCM, use all 13 positions from device_positions_6
device_positions = device_positions_6[:13]
label_positions = label_positions_6[:13]
else:
# For 9-12, use first view.json (updated) up to DPM12, then placeholders
device_positions = device_positions_1[:min(dpm_count, 12)]
label_positions = label_positions_1[:min(dpm_count, 12)]
# Extend for DPM13+ with placeholders (should not be used now)
for i in range(12, dpm_count):
device_positions.append({"x": 0.1 * (i % 5), "y": 0.3333 * (i // 5), "width": 0.25, "height": 0.3333})
label_positions.append({"x": 0.1 * (i % 5), "y": 0.3333 * (i // 5) + 0.1, "width": 0.0547, "height": 0.0358})
return device_positions, label_positions
def make_binding(path):
return {"binding": {"config": {"path": path}, "type": "property"}}
def make_connection(view, name, tag_index):
view["custom"][name] = False
view["propConfig"][f"custom.{name}"] = {
"binding": {
"config": {
"fallbackDelay": 2.5,
"mode": "indirect",
"references": {
str(tag_index): f"{{view.params.tagProps[{tag_index}]}}",
"fc": "{session.custom.fc}",
},
"tagPath": f"[{{fc}}_SCADA_TAG_PROVIDER]{{{tag_index}}}/STATE"
},
"transforms": [
{"expression": "coalesce({value},{view.params.forceFaultStatus},1)", "type": "expression"},
{"fallback": False, "inputType": "scalar", "mappings": [{"input": 0, "output": True}, {"input": 1, "output": False}], "outputType": "scalar", "type": "map"}
],
"type": "tag"
},
"persistent": True
}
def generate_view_json(dpm_count, dpm_texts, dpm_device_names, mcm_name):
device_positions, label_positions = get_dpm_positions(dpm_count)
mcm_last = (dpm_count == 12)
view = {
"custom": {},
"params": {"tagProps": [f"DPM{i}_TAG" for i in range(dpm_count)]},
"propConfig": {},
"props": {"defaultSize": {"height": 894, "width": 1920}},
"root": {"children": [], "meta": {"name": "root"}, "position": {"x": 120, "y": -723}, "props": {"mode": "percent", "style": {"backgroundColor": "#ffffff"}}, "type": "ia.container.coord"}
}
# Connections
# mcm-dpm1
make_connection(view, "mcm-dpm1", 0)
# dpm1-dpm2, dpm2-dpm3, ..., dpm{max-1}-dpm{max}
for i in range(1, dpm_count - 1):
make_connection(view, f"dpm{i}-dpm{i+1}", i)
# dpm{max}-mcm
make_connection(view, f"dpm{dpm_count-1}-mcm", dpm_count-1)
view["propConfig"]["params.tagProps"] = {"paramDirection": "input", "persistent": True}
default_params = {
"InDown": False, "InLeft": False, "InUp": False,
"OutDown": False, "OutRight": False, "OutUp": False,
"Down1": False, "Down2": False, "Down3": False,
"DownLeft": False, "DownOn": False, "DownRight": False
}
# Devices
for i in range(dpm_count):
if mcm_last:
# MCM last: DPMs 0-10, MCM 11
if i == dpm_count - 1:
# MCM
device_name = "MCM"
label_text = "MCM"
entry = {
"events": {"dom": {"onClick": {"config": {"script": "\tself.session.custom.dpm_view_path = self.props.params.view\n\tself.session.custom.show_dpm_device_view = True"}, "scope": "G", "type": "script"}}},
"meta": {"name": device_name},
"position": device_positions[i],
"propConfig": {},
"props": {"params": {"InDown": False, "InLeft": False, "InOn": False, "InUp": False, "OutDown": False, "OutRight": False, "OutUp": False},
"path": "Windows/Tabs/Enternet Windows/Components/EN4TR"},
"type": "ia.display.view"
}
entry["propConfig"]["props.params.InOn"] = make_binding("view.custom.dpm11-mcm")
entry["propConfig"]["props.params.OutOn"] = make_binding("view.custom.mcm-dpm1")
else:
device_name = dpm_device_names[i]
label_text = dpm_texts[i]
params = default_params.copy()
params["view"] = f"Windows/Tabs/Enternet Windows/DPMs/DPM Devices/{mcm_name}/{device_name}"
entry = {
"events": {"dom": {"onClick": {"config": {"script": "\tself.session.custom.dpm_view_path = self.props.params.view\n\tself.session.custom.show_dpm_device_view = True"}, "scope": "G", "type": "script"}}},
"meta": {"name": device_name},
"position": device_positions[i],
"propConfig": {},
"props": {
"params": params,
"path": "Windows/Tabs/Enternet Windows/Components/DPM_BLOCK"
},
"type": "ia.display.view"
}
# DPM1
if i == 0:
entry["propConfig"]["props.params.InOn"] = make_binding("view.custom.dpm1-dpm2")
entry["propConfig"]["props.params.OutOn"] = make_binding("view.custom.mcm-dpm1")
# DPM2..DPM10
elif 1 <= i <= 9:
entry["propConfig"]["props.params.InOn"] = make_binding(f"view.custom.dpm{i+1}-dpm{i+2}")
entry["propConfig"]["props.params.OutOn"] = make_binding(f"view.custom.dpm{i}-dpm{i+1}")
# DPM11
elif i == 10:
entry["propConfig"]["props.params.InOn"] = make_binding("view.custom.dpm10-dpm11")
entry["propConfig"]["props.params.OutOn"] = make_binding("view.custom.dpm11-mcm")
view["root"]["children"].append(entry)
else:
# Default: MCM is first
is_mcm = (i == 0)
if is_mcm:
device_name = "MCM"
label_text = "MCM"
entry = {
"events": {"dom": {"onClick": {"config": {"script": "\tself.session.custom.dpm_view_path = self.props.params.view\n\tself.session.custom.show_dpm_device_view = True"}, "scope": "G", "type": "script"}}},
"meta": {"name": device_name},
"position": device_positions[i],
"propConfig": {},
"props": {"params": {"InDown": False, "InLeft": False, "InOn": False, "InUp": False, "OutDown": False, "OutRight": False, "OutUp": False},
"path": "Windows/Tabs/Enternet Windows/Components/EN4TR"},
"type": "ia.display.view"
}
entry["propConfig"]["props.params.InOn"] = make_binding(f"view.custom.dpm{dpm_count-1}-mcm")
entry["propConfig"]["props.params.OutOn"] = make_binding("view.custom.mcm-dpm1")
else:
device_name = dpm_device_names[i-1]
label_text = dpm_texts[i-1]
params = default_params.copy()
params["view"] = f"Windows/Tabs/Enternet Windows/DPMs/DPM Devices/{mcm_name}/{device_name}"
entry = {
"events": {"dom": {"onClick": {"config": {"script": "\tself.session.custom.dpm_view_path = self.props.params.view\n\tself.session.custom.show_dpm_device_view = True"}, "scope": "G", "type": "script"}}},
"meta": {"name": device_name},
"position": device_positions[i],
"propConfig": {},
"props": {
"params": params,
"path": "Windows/Tabs/Enternet Windows/Components/DPM_BLOCK"
},
"type": "ia.display.view"
}
# DPM1
if i == 1:
entry["propConfig"]["props.params.InOn"] = make_binding("view.custom.dpm1-dpm2")
entry["propConfig"]["props.params.OutOn"] = make_binding("view.custom.mcm-dpm1")
# Last DPM
elif i == dpm_count - 1:
entry["propConfig"]["props.params.InOn"] = make_binding(f"view.custom.dpm{dpm_count-2}-dpm{dpm_count-1}")
entry["propConfig"]["props.params.OutOn"] = make_binding(f"view.custom.dpm{dpm_count-1}-mcm")
# Middle DPMs
else:
entry["propConfig"]["props.params.InOn"] = make_binding(f"view.custom.dpm{i}-dpm{i+1}")
entry["propConfig"]["props.params.OutOn"] = make_binding(f"view.custom.dpm{i-1}-dpm{i}")
view["root"]["children"].append(entry)
# Labels
if mcm_last:
for i in range(dpm_count - 1): # 0 to 10 for 11 DPMs
view["root"]["children"].append({
"meta": {"name": f"DPM{i+1}_label"},
"position": label_positions[i],
"props": {"text": dpm_texts[i], "textStyle": {"fontSize": "1vmin"}},
"type": "ia.display.label"
})
else:
for i in range(1, dpm_count):
view["root"]["children"].append({
"meta": {"name": f"DPM{i}_label"},
"position": label_positions[i],
"props": {"text": dpm_texts[i-1], "textStyle": {"fontSize": "1vmin"}},
"type": "ia.display.label"
})
return view
def main():
try:
mcm_name = input("Enter MCM name [Ex. MCM01]: ").strip()
if not mcm_name:
print("Error: MCM name cannot be empty.")
return
print("Enter DPMs (one per line, format: <device_name> <device_ip>). Leave blank line to finish.")
lines = []
while True:
line = input()
if not line.strip():
break
lines.append(line.strip())
dpm_count = len(lines) + 1
if dpm_count < 2:
print("Error: You must enter at least one DPM.")
return
dpm_device_names, dpm_texts = [], []
for entry in lines:
if '\t' in entry:
device_name, _ = entry.split('\t', 1)
elif ' ' in entry:
device_name, _ = entry.split(' ', 1)
else:
print(f"Error: '{entry}' is missing a separator (tab or space) between device name and full text.")
return
dpm_device_names.append(device_name)
dpm_texts.append(entry)
view = generate_view_json(dpm_count, dpm_texts, dpm_device_names, mcm_name)
with open("view.json", "w") as f:
json.dump(view, f, indent=2)
print(f"Successfully generated view.json with {dpm_count-1} DPMs + 1 MCM")
except Exception as e:
print(f"An error occurred: {str(e)}")
if __name__ == "__main__":
main()