374 lines
20 KiB
Python
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()
|
|
|