Files
V-Fire-Monitor/tools/build_floorplan_bundle.py
T

121 lines
3.8 KiB
Python

import argparse
import json
from pathlib import Path
VALID_ICONS = {
"detector-smoke",
"detector-heat",
"module-input",
"siren",
"panel-nfs320",
}
def parse_args():
parser = argparse.ArgumentParser(description="Gera bundle versionavel de planta baixa para o Grafana")
parser.add_argument("spec", help="Arquivo JSON com o mapa da planta")
parser.add_argument(
"--output",
help="Arquivo de saida. Default: mesmo nome com sufixo .bundle.json",
)
return parser.parse_args()
def validate_item(item: dict, seen_ids: set[str]) -> dict:
item_id = str(item.get("id", "")).strip()
if not item_id:
raise ValueError("Cada item precisa de id.")
if item_id in seen_ids:
raise ValueError(f"Item duplicado: {item_id}")
seen_ids.add(item_id)
icon = str(item.get("icon", "")).strip()
if icon not in VALID_ICONS:
raise ValueError(f"Icone invalido para item {item_id}: {icon}")
label = str(item.get("label", "")).strip()
item_key = str(item.get("item_key", "")).strip()
if not label:
raise ValueError(f"Label obrigatorio para item {item_id}.")
if not item_key:
raise ValueError(f"item_key obrigatorio para item {item_id}.")
for field in ("x", "y", "width", "height"):
value = item.get(field)
if not isinstance(value, int) or value < 0:
raise ValueError(f"Campo {field} invalido para item {item_id}.")
rotation = item.get("rotation", 0)
if not isinstance(rotation, int):
raise ValueError(f"rotation invalido para item {item_id}.")
return {
"id": item_id,
"label": label,
"item_key": item_key,
"icon": icon,
"x": item["x"],
"y": item["y"],
"width": item["width"],
"height": item["height"],
"rotation": rotation,
}
def build_bundle(spec: dict) -> dict:
title = str(spec.get("title", "")).strip()
dashboard_uid = str(spec.get("grafana_dashboard_uid", "")).strip()
background_image_url = str(spec.get("background_image_url", "")).strip()
vfire_base_url = str(spec.get("vfire_base_url", "")).rstrip("/")
zabbix_host = str(spec.get("zabbix_host", "")).strip()
if not title:
raise ValueError("title obrigatorio.")
if not dashboard_uid:
raise ValueError("grafana_dashboard_uid obrigatorio.")
if not background_image_url:
raise ValueError("background_image_url obrigatorio.")
if not vfire_base_url:
raise ValueError("vfire_base_url obrigatorio.")
if not zabbix_host:
raise ValueError("zabbix_host obrigatorio.")
raw_items = spec.get("items")
if not isinstance(raw_items, list) or not raw_items:
raise ValueError("items deve conter ao menos um elemento.")
seen_ids: set[str] = set()
items = [validate_item(item, seen_ids) for item in raw_items]
for item in items:
item["icon_url"] = f"{vfire_base_url}/static/grafana-icons/{item['icon']}.svg"
item["zabbix_ref"] = {
"host": zabbix_host,
"item_key": item["item_key"],
}
return {
"title": title,
"grafana_dashboard_uid": dashboard_uid,
"background_image_url": background_image_url,
"vfire_base_url": vfire_base_url,
"zabbix_host": zabbix_host,
"items": items,
}
def main():
args = parse_args()
spec_path = Path(args.spec)
output_path = Path(args.output) if args.output else spec_path.with_suffix(".bundle.json")
spec = json.loads(spec_path.read_text(encoding="utf-8"))
bundle = build_bundle(spec)
output_path.parent.mkdir(parents=True, exist_ok=True)
output_path.write_text(json.dumps(bundle, indent=2, ensure_ascii=False), encoding="utf-8")
print(output_path)
if __name__ == "__main__":
main()