j0h

MCP_E360_unit3_monitor

j0h
Apr 15th, 2026
138
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.05 KB | None | 0 0
  1. #!/usr/bin/env python3
  2. import csv, time, os, datetime, itertools
  3. import matplotlib.pyplot as plt
  4. try:
  5.     from fc6a import FC6AMaint
  6. except ImportError:
  7.     print("fc6a module not found, downloading from GitHub...")
  8.     import requests
  9.     url = "https://raw.githubusercontent.com/Makerspace-Bangor/fc6a/main/src/fc6a.py"
  10.     code = requests.get(url).text
  11.     exec(code, globals())  # inject FC6AMaint
  12.     print("fc6a module loaded from GitHub.")
  13.  
  14.  
  15. PLC_CONFIGS = [
  16.     {
  17.         "name": "MCP6",
  18.         "ip": "192.168.1.50",
  19.         "device": "FF",
  20.         "endian": "0",
  21.         "registers": [
  22.             ("heatCall3","D0155.00","B"),  
  23.             ("TempSetpoint","D0710","F"),  
  24.             ("hp3_Connect", "M8347", "B"),
  25.             ("UnitCall3", "D0155", "W"),
  26.             ("runHrs3","D1003","W"),
  27.             ("UnitNeeded","D10033","W"),
  28.             ("Cycle","M0002","B"),
  29.             ("MCP_Alarm","M0064","B"),
  30.             ("Alarm3","D0140","W"),
  31.         ],
  32.     }
  33. ]
  34.  
  35.  
  36.  
  37. """
  38. PLC_CONFIGS = [
  39.    {
  40.        "name": "hp1",
  41.        "ip": "192.168.1.1",
  42.        "device": "FF",
  43.        "endian": "1",
  44.        "registers": [
  45.            ("Rio1", "D0516", "F"),
  46.        ],
  47.    },
  48.    {
  49.        "name": "Hp2",
  50.        "ip": "192.168.1.3",
  51.        "device": "FF",
  52.        "endian": "1",
  53.        "registers": [
  54.            ("Rio2", "D0516", "F"),
  55.        ],
  56.    },
  57.    {
  58.        "name": "HP3",
  59.        "ip": "192.168.1.4",
  60.        "device": "FF",
  61.        "endian": "1",
  62.        "registers": [
  63.            ("Rio3", "D0516", "F"),
  64.        ],
  65.    },
  66.    {
  67.        "name": "MCP6",
  68.        "ip": "192.168.1.50",
  69.        "device": "FF",
  70.        "endian": "0",
  71.        "registers": [
  72.            ("hp1_stat", "M8345", "B"),
  73.            ("hp2_stat", "M8346", "B"),
  74.            ("hp3_stat", "M8347", "B"),
  75.        ],
  76.    }
  77. ]
  78. """
  79. def get_csv_filename(cfg):
  80.     date_str = datetime.date.today().strftime("%Y-%m-%d")
  81.     return f"{cfg['name']}_{{date_str}}.csv"
  82.  
  83. def ensure_csv_header(filename, fieldnames):
  84.     if not os.path.exists(filename):
  85.         with open(filename, "w", newline="") as f:
  86.             csv.DictWriter(f, fieldnames=fieldnames).writeheader()
  87.  
  88. def read_plc_values(cfg):
  89.     plc = FC6AMaint(cfg["ip"])
  90.     swapped = bool(int(cfg.get("endian", "0")))
  91.     data = {}
  92.     for tag, reg, dtype in cfg["registers"]:
  93.         try:
  94.             rnum = int(reg[1:])
  95.             if dtype == "F":
  96.                 val = round(plc.read_float(rnum, swapped), 2)
  97.             elif dtype == "W":
  98.                 val = plc.read_word(rnum)
  99.             elif dtype == "B":
  100.                 val = plc.read_bits(rnum)
  101.             else:
  102.                 val = None
  103.         except Exception as e:
  104.             print(f"Error reading {tag} from {cfg['name']}: {e}")
  105.             val = None
  106.         data[tag] = val
  107.     return data
  108.  
  109. def main():
  110.     # Limit to 5 PLCs max
  111.     active_plcs = PLC_CONFIGS[:5]
  112.     colors = itertools.cycle(["red", "green", "purple", "orange", "pink"])
  113.  
  114.     # Collect all unique tag names
  115.     unique_tags = sorted(set(tag for cfg in active_plcs for tag, _, _ in cfg["registers"]))
  116.     n = len(unique_tags)
  117.     fig, axes = plt.subplots(n, 1, figsize=(10, n * 2.5), sharex=True)
  118.     if n == 1:
  119.         axes = [axes]
  120.  
  121.     fig.suptitle("Multi-PLC Live Trends (1 Hz)")
  122.     plt.ion()
  123.  
  124.     timestamps = []
  125.     values = {tag: {cfg["name"]: [] for cfg in active_plcs} for tag in unique_tags}
  126.     plc_colors = {cfg["name"]: next(colors) for cfg in active_plcs}
  127.  
  128.     while True:
  129.         now = datetime.datetime.now()
  130.         timestamps.append(now)
  131.         timestamps = timestamps[-3600:]
  132.  
  133.         # read each PLC and update stored values
  134.         for cfg in active_plcs:
  135.             row = read_plc_values(cfg)
  136.             for tag, val in row.items():
  137.                 if tag not in values:
  138.                     continue
  139.                 values[tag][cfg["name"]].append(val)
  140.                 # keep history length equal to timestamps
  141.                 if len(values[tag][cfg["name"]]) > len(timestamps):
  142.                     values[tag][cfg["name"]] = values[tag][cfg["name"]][-len(timestamps):]
  143.  
  144.         # redraw all tag subplots
  145.         for i, tag in enumerate(unique_tags):
  146.             ax = axes[i]
  147.             ax.clear()
  148.             for cfg in active_plcs:
  149.                 series = values[tag][cfg["name"]]
  150.                 # only plot if we have at least one valid data point
  151.                 if not series:
  152.                     continue
  153.                 # align list lengths safely
  154.                 y = series[-len(timestamps):]
  155.                 x = timestamps[-len(y):]
  156.                 color = plc_colors[cfg["name"]]
  157.                 ax.plot(x, y, label=cfg["name"], color=color)
  158.             ax.set_ylabel(tag)
  159.             ax.legend(loc="upper right")
  160.             ax.grid(True)
  161.  
  162.         axes[-1].set_xlabel("Time")
  163.         plt.tight_layout()
  164.         plt.pause(0.1)
  165.         time.sleep(1)
  166.  
  167.        
  168. if __name__ == "__main__":
  169.     try:
  170.         main()
  171.     except KeyboardInterrupt:
  172.         print("\nExiting gracefully.")
  173.  
Advertisement
Add Comment
Please, Sign In to add comment