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: ). 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()