You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
164 lines
6.3 KiB
Python
164 lines
6.3 KiB
Python
import json
|
|
from collections import defaultdict
|
|
from sqlalchemy import create_engine, text
|
|
|
|
# 🔧 Adjust this to your environment
|
|
DB_URL = "postgresql+psycopg2://postgres:postgres@192.168.1.86:5432/digital_aeros_fixed"
|
|
|
|
def export_rbd_json(project_id, output_file="rbd.json"):
|
|
engine = create_engine(DB_URL)
|
|
|
|
with engine.connect() as conn:
|
|
# --- Project info ---
|
|
project = conn.execute(
|
|
text('SELECT "ProjectId","ProjectName" FROM public."Projects" WHERE "ProjectId" = :pid'),
|
|
{"pid": project_id}
|
|
).mappings().first()
|
|
if not project:
|
|
raise ValueError(f"❌ Project {project_id} not found")
|
|
|
|
print(f"🔍 Loaded project: {project['ProjectName']} (ID={project_id})")
|
|
|
|
# --- Schematics ---
|
|
schematics = conn.execute(
|
|
text('SELECT "SchematicId","SchematicName" FROM public."Schematics" WHERE "ProjectId" = :pid'),
|
|
{"pid": project_id}
|
|
).mappings().all()
|
|
|
|
all_schematics_json = {}
|
|
|
|
for s in schematics:
|
|
sid = s["SchematicId"]
|
|
sname = s["SchematicName"]
|
|
print(f"\n=== Processing schematic {sid} ({sname}) ===")
|
|
|
|
# --- Nodes ---
|
|
nodes_data = conn.execute(
|
|
text('SELECT "NodeId","NodeUIId","NodeName","NodeTypeCode" '
|
|
'FROM public."RegularNodes" WHERE "SchematicId" = :sid'),
|
|
{"sid": sid}
|
|
).mappings().all()
|
|
|
|
# dict keyed by NodeId
|
|
nodes = {str(n["NodeId"]): dict(n) for n in nodes_data}
|
|
# map UIId -> NodeId
|
|
uiid_to_id = {str(n["NodeUIId"]): str(n["NodeId"]) for n in nodes_data}
|
|
|
|
print(f"🟦 Nodes: {len(nodes)}")
|
|
|
|
# --- Connectors (edges) ---
|
|
edges = conn.execute(
|
|
text('SELECT "SourceUIId","SinkUIId" FROM public."Connectors" WHERE "SchematicId" = :sid'),
|
|
{"sid": sid}
|
|
).mappings().all()
|
|
|
|
children_map = defaultdict(list)
|
|
for e in edges:
|
|
src_ui = str(e["SourceUIId"])
|
|
sink_ui = str(e["SinkUIId"])
|
|
if src_ui in uiid_to_id and sink_ui in uiid_to_id:
|
|
src_id = uiid_to_id[src_ui]
|
|
sink_id = uiid_to_id[sink_ui]
|
|
children_map[src_id].append(sink_id)
|
|
|
|
print(f"🔗 Connectors: {len(edges)}")
|
|
|
|
# --- Redundancies ---
|
|
redundancies = conn.execute(
|
|
text('SELECT * FROM public."Redundancies" WHERE "SchematicId" = :sid'),
|
|
{"sid": sid}
|
|
).mappings().all()
|
|
|
|
states = conn.execute(
|
|
text('SELECT * FROM public."RedundancyStates" WHERE "RedundancyId" IN '
|
|
'(SELECT "RedundancyId" FROM public."Redundancies" WHERE "SchematicId" = :sid)'),
|
|
{"sid": sid}
|
|
).mappings().all()
|
|
|
|
state_cells = conn.execute(
|
|
text('SELECT * FROM public."RedundancyStateCells" WHERE "RedundancyStateId" IN '
|
|
'(SELECT "StateId" FROM public."RedundancyStates" WHERE "RedundancyId" IN '
|
|
'(SELECT "RedundancyId" FROM public."Redundancies" WHERE "SchematicId" = :sid))'),
|
|
{"sid": sid}
|
|
).mappings().all()
|
|
|
|
# Build redundancy structure
|
|
redundancy_map = {}
|
|
for r in redundancies:
|
|
rid = str(r["RedundancyId"])
|
|
redundancy_map[rid] = {
|
|
"name": r["RedundancyName"],
|
|
"type": "standby" if r["IsKNStandby"] else "kofn",
|
|
"min_required": r["MinRequiredNodes"],
|
|
"switch_delay": r["SwitchDelay"],
|
|
"states": {}
|
|
}
|
|
|
|
for st in states:
|
|
sid2 = str(st["StateId"])
|
|
rid = str(st["RedundancyId"])
|
|
redundancy_map[rid]["states"][sid2] = {
|
|
"priority": st["StatePriority"],
|
|
"duration": st["StateDuration"],
|
|
"cells": []
|
|
}
|
|
|
|
for c in state_cells:
|
|
sid2 = str(c["RedundancyStateId"])
|
|
for r_id, r in redundancy_map.items():
|
|
if sid2 in r["states"]:
|
|
node_id = str(c["InvolvedNodeId"])
|
|
if node_id in nodes: # only link if valid
|
|
r["states"][sid2]["cells"].append({
|
|
"node_id": node_id,
|
|
"status": c["NodeStatusCode"]
|
|
})
|
|
break
|
|
|
|
# --- Build JSON nodes ---
|
|
json_nodes = {}
|
|
for node_id, n in nodes.items():
|
|
node_type = str(n["NodeTypeCode"]).lower()
|
|
node_json = {
|
|
"type": node_type,
|
|
"name": n["NodeName"],
|
|
"children": children_map.get(node_id, []), # now NodeId-based
|
|
"availability": 1.0 # ✅ default availability
|
|
}
|
|
json_nodes[node_id] = node_json
|
|
|
|
# --- Root detection ---
|
|
all_children = {c for lst in children_map.values() for c in lst}
|
|
root_candidates = [nid for nid in nodes.keys() if nid not in all_children]
|
|
root = root_candidates[0] if root_candidates else None
|
|
print(f"🌳 Root node detected: {root}")
|
|
|
|
# --- Assemble schematic JSON ---
|
|
schematic_json = {
|
|
"schematic_id": sid,
|
|
"schematic_name": sname,
|
|
"root": str(root) if root else None,
|
|
"nodes": json_nodes,
|
|
"redundancies": redundancy_map
|
|
}
|
|
all_schematics_json[str(sid)] = schematic_json
|
|
|
|
print(f"✅ Finished schematic {sid}")
|
|
|
|
# --- Final JSON ---
|
|
final_json = {
|
|
"project_id": project["ProjectId"],
|
|
"project_name": project["ProjectName"],
|
|
"schematics": all_schematics_json
|
|
}
|
|
|
|
with open(output_file, "w") as f:
|
|
json.dump(final_json, f, indent=2)
|
|
|
|
print(f"\n🎉 Exported simplified RBD JSON (NodeId-based, availability=1.0) "
|
|
f"for Project {project_id} → {output_file}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
export_rbd_json(project_id=70, output_file="project_70_rbd.json")
|