Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env python3
- import csv, time, os, datetime, itertools
- import matplotlib.pyplot as plt
- try:
- from fc6a import FC6AMaint
- except ImportError:
- print("fc6a module not found, downloading from GitHub...")
- import requests
- url = "https://raw.githubusercontent.com/Makerspace-Bangor/fc6a/main/src/fc6a.py"
- code = requests.get(url).text
- exec(code, globals()) # inject FC6AMaint
- print("fc6a module loaded from GitHub.")
- PLC_CONFIGS = [
- {
- "name": "MCP6",
- "ip": "192.168.1.50",
- "device": "FF",
- "endian": "0",
- "registers": [
- ("heatCall3","D0155.00","B"),
- ("TempSetpoint","D0710","F"),
- ("hp3_Connect", "M8347", "B"),
- ("UnitCall3", "D0155", "W"),
- ("runHrs3","D1003","W"),
- ("UnitNeeded","D10033","W"),
- ("Cycle","M0002","B"),
- ("MCP_Alarm","M0064","B"),
- ("Alarm3","D0140","W"),
- ],
- }
- ]
- """
- PLC_CONFIGS = [
- {
- "name": "hp1",
- "ip": "192.168.1.1",
- "device": "FF",
- "endian": "1",
- "registers": [
- ("Rio1", "D0516", "F"),
- ],
- },
- {
- "name": "Hp2",
- "ip": "192.168.1.3",
- "device": "FF",
- "endian": "1",
- "registers": [
- ("Rio2", "D0516", "F"),
- ],
- },
- {
- "name": "HP3",
- "ip": "192.168.1.4",
- "device": "FF",
- "endian": "1",
- "registers": [
- ("Rio3", "D0516", "F"),
- ],
- },
- {
- "name": "MCP6",
- "ip": "192.168.1.50",
- "device": "FF",
- "endian": "0",
- "registers": [
- ("hp1_stat", "M8345", "B"),
- ("hp2_stat", "M8346", "B"),
- ("hp3_stat", "M8347", "B"),
- ],
- }
- ]
- """
- def get_csv_filename(cfg):
- date_str = datetime.date.today().strftime("%Y-%m-%d")
- return f"{cfg['name']}_{{date_str}}.csv"
- def ensure_csv_header(filename, fieldnames):
- if not os.path.exists(filename):
- with open(filename, "w", newline="") as f:
- csv.DictWriter(f, fieldnames=fieldnames).writeheader()
- def read_plc_values(cfg):
- plc = FC6AMaint(cfg["ip"])
- swapped = bool(int(cfg.get("endian", "0")))
- data = {}
- for tag, reg, dtype in cfg["registers"]:
- try:
- rnum = int(reg[1:])
- if dtype == "F":
- val = round(plc.read_float(rnum, swapped), 2)
- elif dtype == "W":
- val = plc.read_word(rnum)
- elif dtype == "B":
- val = plc.read_bits(rnum)
- else:
- val = None
- except Exception as e:
- print(f"Error reading {tag} from {cfg['name']}: {e}")
- val = None
- data[tag] = val
- return data
- def main():
- # Limit to 5 PLCs max
- active_plcs = PLC_CONFIGS[:5]
- colors = itertools.cycle(["red", "green", "purple", "orange", "pink"])
- # Collect all unique tag names
- unique_tags = sorted(set(tag for cfg in active_plcs for tag, _, _ in cfg["registers"]))
- n = len(unique_tags)
- fig, axes = plt.subplots(n, 1, figsize=(10, n * 2.5), sharex=True)
- if n == 1:
- axes = [axes]
- fig.suptitle("Multi-PLC Live Trends (1 Hz)")
- plt.ion()
- timestamps = []
- values = {tag: {cfg["name"]: [] for cfg in active_plcs} for tag in unique_tags}
- plc_colors = {cfg["name"]: next(colors) for cfg in active_plcs}
- while True:
- now = datetime.datetime.now()
- timestamps.append(now)
- timestamps = timestamps[-3600:]
- # read each PLC and update stored values
- for cfg in active_plcs:
- row = read_plc_values(cfg)
- for tag, val in row.items():
- if tag not in values:
- continue
- values[tag][cfg["name"]].append(val)
- # keep history length equal to timestamps
- if len(values[tag][cfg["name"]]) > len(timestamps):
- values[tag][cfg["name"]] = values[tag][cfg["name"]][-len(timestamps):]
- # redraw all tag subplots
- for i, tag in enumerate(unique_tags):
- ax = axes[i]
- ax.clear()
- for cfg in active_plcs:
- series = values[tag][cfg["name"]]
- # only plot if we have at least one valid data point
- if not series:
- continue
- # align list lengths safely
- y = series[-len(timestamps):]
- x = timestamps[-len(y):]
- color = plc_colors[cfg["name"]]
- ax.plot(x, y, label=cfg["name"], color=color)
- ax.set_ylabel(tag)
- ax.legend(loc="upper right")
- ax.grid(True)
- axes[-1].set_xlabel("Time")
- plt.tight_layout()
- plt.pause(0.1)
- time.sleep(1)
- if __name__ == "__main__":
- try:
- main()
- except KeyboardInterrupt:
- print("\nExiting gracefully.")
Advertisement
Add Comment
Please, Sign In to add comment