- build_controllers_config.py: gateway-config.json 생성 - load_map_master.py: hc900_map_master 테이블 적재 - measure_scan_time.py: HC900 스캔 시간 측정 유틸
108 lines
4.1 KiB
Python
108 lines
4.1 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Load hc900_map_master from the per-controller register maps (register-map-c{n}.json).
|
|
|
|
hc900_map_master is the DB table the web UI "태그 관리" (Tag Management) tab reads and
|
|
the realtime service uses to know which tags to poll (it sends ``hc900_tag`` to the
|
|
gateway's ReadTags). So ``hc900_tag`` must match the gateway's register-map tag — i.e.
|
|
the Experion point name (e.g. FICQ-6101.PV). We set ``tagname == hc900_tag`` so the
|
|
realtime_table (keyed by tagname) lines up with both.
|
|
|
|
Usage:
|
|
python3 load_map_master.py --controller C3 --map docs/register-map-c3.json
|
|
python3 load_map_master.py --from-config config/gateway-config.json # all enabled
|
|
"""
|
|
|
|
import re
|
|
import json
|
|
import argparse
|
|
from pathlib import Path
|
|
|
|
import psycopg2
|
|
|
|
DSN = dict(host="localhost", port=5432, dbname="iiot_platform",
|
|
user="postgres", password="postgres")
|
|
|
|
# Experion point-parameter suffix → param_type used by the UI for grouping/colours.
|
|
_PARAM_ALIAS = {"MD": "MODE"}
|
|
|
|
|
|
def classify(entry: dict) -> tuple[str, int | None]:
|
|
"""Return (param_type, loop_no) for a register entry."""
|
|
tag = entry["tag"]
|
|
desc = entry.get("description", "")
|
|
if desc.startswith("LOOP"):
|
|
m = re.search(r"#(\d+)", desc)
|
|
loop = int(m.group(1)) if m else None
|
|
suffix = tag.rsplit(".", 1)[1] if "." in tag else "LOOP"
|
|
return _PARAM_ALIAS.get(suffix, suffix), loop
|
|
if "Signal Tag" in desc:
|
|
return "SIG", None
|
|
if "Variable" in desc:
|
|
return "VAR", None
|
|
if "Custom" in desc:
|
|
return "RAW", None
|
|
suffix = tag.rsplit(".", 1)[1] if "." in tag else "OTHER"
|
|
return _PARAM_ALIAS.get(suffix, suffix), None
|
|
|
|
|
|
def load_controller(cur, controller: str, map_path: Path, active: bool) -> int:
|
|
data = json.loads(map_path.read_text(encoding="utf-8"))
|
|
cur.execute("DELETE FROM hc900_map_master WHERE controller_id = %s", (controller,))
|
|
n = 0
|
|
for e in data["registers"]:
|
|
param_type, loop_no = classify(e)
|
|
access = "R/W" if e.get("access") == "RW" else "R"
|
|
# Single consistent name everywhere: tagname == hc900_tag == the register tag
|
|
# (Experion ItemName, e.g. FICQ-6101.PV) — used by the gateway, map_master and
|
|
# realtime_table alike. No case conversion.
|
|
cur.execute(
|
|
"""INSERT INTO hc900_map_master
|
|
(tagname, hc900_tag, modbus_addr, data_type, access,
|
|
is_active, loop_no, param_type, controller_id)
|
|
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)""",
|
|
(e["tag"], e["tag"], e["addr"], e["type"], access,
|
|
active, loop_no, param_type, controller))
|
|
n += 1
|
|
return n
|
|
|
|
|
|
def main():
|
|
p = argparse.ArgumentParser(description="Load hc900_map_master from register maps")
|
|
p.add_argument("--controller", help="controller id, e.g. C3")
|
|
p.add_argument("--map", help="register-map json for --controller")
|
|
p.add_argument("--from-config", help="gateway-config.json: load every enabled controller")
|
|
p.add_argument("--inactive", action="store_true",
|
|
help="insert rows as is_active=false (default: active)")
|
|
args = p.parse_args()
|
|
|
|
jobs: list[tuple[str, Path]] = []
|
|
if args.from_config:
|
|
cfg = json.loads(Path(args.from_config).read_text(encoding="utf-8"))
|
|
for c in cfg.get("controllers", []):
|
|
if c.get("enabled", True):
|
|
jobs.append((c["id"], Path(c["registerMapPath"])))
|
|
elif args.controller and args.map:
|
|
jobs.append((args.controller, Path(args.map)))
|
|
else:
|
|
p.error("provide --from-config OR (--controller and --map)")
|
|
|
|
conn = psycopg2.connect(**DSN)
|
|
cur = conn.cursor()
|
|
cur.execute("SET search_path TO hc900")
|
|
total = 0
|
|
for ctrl, mp in jobs:
|
|
if not mp.exists():
|
|
print(f" ⚠ {ctrl}: map not found: {mp} — skipping")
|
|
continue
|
|
n = load_controller(cur, ctrl, mp, not args.inactive)
|
|
total += n
|
|
print(f" {ctrl}: {n} rows ← {mp.name}")
|
|
conn.commit()
|
|
conn.close()
|
|
print(f"✓ hc900_map_master loaded: {total} rows total")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|