Update~Read PLC for Chart ~ Log By Shift To be... Alarm AI Machine Learning

上图~
持续迭代
1、增加报警弹窗,具体到哪个值,双边规格具体是多少
2、实时显示当前值的统计特征,Max  Min  AVG ...






import tkinter as tk
from tkinter import simpledialog
import time
import threading
import queue
import logging
from datetime import datetime
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg  # 新增导入
from matplotlib.animation import FuncAnimation
from openpyxl import Workbook, load_workbook
from HslCommunication import MelsecMcNet
import os
import csv
import winsound
import json# 配置日志
logging.basicConfig(level=logging.INFO,format='%(asctime)s.%(msecs)03d %(levelname)s: %(message)s',datefmt='%Y-%m-%d %H:%M:%S'
)
logger = logging.getLogger("PLC_Monitor")# 设置中文字体支持
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False    # 用来正常显示负号class PLCMonitor:def __init__(self):self.is_running = Trueself.is_collecting = Falseself.data_queue = queue.Queue()self.data_points = []self.register_addresses = ["D390", "D391", "D392", "D393", "D394", "D395"]  # 6个默认地址# 新增初始化属性self.current_date = datetime.now().strftime("%Y%m%d")  # 当前日期self.current_shift = self.get_shift()  # 当前班别self.last_shift_check = time.time()  # 上次班别检查时间self.data_dir = "C:\\Log\\Cature_Datawen"  # 数据存储目录# 确保数据目录存在os.makedirs(self.data_dir, exist_ok=True)self.current_filepath = os.path.join(self.data_dir, f"{self.current_date}_{self.current_shift}.txt")  # 初始化文件路径# 初始化图表属性self.fig, self.ax = plt.subplots(figsize=(12, 6))self.fig.patch.set_facecolor('#2E2E2E')  # 设置图表背景色self.canvas = None  # 初始化canvas属性# 创建主窗口self.root = tk.Tk()self.root.title("Design By Tim")self.root.geometry("1200x700")self.root.minsize(1000, 600)self.root.configure(bg='#2E2E2E')# 初始化UI组件self.value_labels = []  # 初始化label列表# 创建图表容器self.chart_frame = tk.Frame(self.root, bg='#2E2E2E')self.chart_frame.pack(side=tk.TOP, fill=tk.BOTH, expand=True, padx=10, pady=10)# 创建值显示区域self.values_frame = tk.Frame(self.root, bg='#2E2E2E')self.values_frame.pack(side=tk.BOTTOM, fill=tk.X, padx=10, pady=10)# 初始化值标签for i in range(6):label = tk.Label(self.values_frame,text="  ",font=('Arial', 12),bg='#2E2E2E',fg='white')label.pack(side=tk.LEFT, padx=10)self.value_labels.append(label)# 添加analysis按钮 (位置保持不变)self.analysis_button = tk.Button(self.chart_frame,text="analysis",command=self.launch_analysis,font=('Arial', 10),bg='#4E4E4E',fg='white')self.analysis_button.pack(side=tk.TOP, anchor=tk.NE, padx=10, pady=6)  # 修改位置到右上角# 添加By Chart按钮 (新位置)self.chart_button = tk.Button(self.chart_frame,text="By Chart",command=self.create_subplots,font=('Arial', 10),bg='#4E4E4E',fg='white')self.chart_button.pack(side=tk.TOP, anchor=tk.NE, padx=10, pady=5)# 添加Alarm Setting按钮 (位置保持不变)self.alarm_button = tk.Button(self.chart_frame,text="Alarm Setting",command=self.open_alarm_settings,font=('Arial', 10),bg='#4E4E4E',fg='white')self.alarm_button.pack(side=tk.TOP, anchor=tk.NE, padx=10, pady=5)# 创建图表self.canvas = FigureCanvasTkAgg(self.fig, master=self.chart_frame)self.canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)# 隐藏初始的Tk窗口self.root.withdraw()# 获取PLC连接参数self.plc_ip = simpledialog.askstring("PLC Par", "PLC_IP:", initialvalue="192.168.0.11",parent=self.root)self.plc_port = simpledialog.askinteger("PLC Par", "PLC_Port:", initialvalue=1028,parent=self.root)# 获取采集信号配置self.start_signal = simpledialog.askstring("Signal ","Start_signal addresses(Y70):",initialvalue="Y70",parent=self.root)self.stop_signal = simpledialog.askstring("Signal ","Stop_signal addresses(Y75):",initialvalue="Y75",parent=self.root)try:self.plc = MelsecMcNet(self.plc_ip, self.plc_port)if not self.plc.ConnectServer().IsSuccess:logger.error("PLC Content NG")self.is_running = Falseelse:logger.info(f"PLC Content OK: {self.plc_ip}:{self.plc_port}")logger.info(f"Start_signal: {self.start_signal}, Stop_signal: {self.stop_signal}")except Exception as e:logger.error(f"PLC Content Error: {str(e)}")self.is_running = False# 获取寄存器配置register_input = simpledialog.askstring("Addresses Config", "Addresses(Max 6,Betwin ,):",initialvalue="D390,D391,D392,D393,D394,D395")if register_input:addresses = [addr.strip() for addr in register_input.split(',')][:6]  # 修改为最多6个地址self.register_addresses = addresseslogger.info(f"Addresses Config: {', '.join(addresses)}")# Initialize alarm settingsself.alarm_settings = {addr: {'upper': float('inf'), 'lower': -float('inf')} for addr in self.register_addresses}self.alarm_active = {addr: False for addr in self.register_addresses}# 加载保存的报警设置self.load_alarm_settings()def open_alarm_settings(self):"""打开报警设置弹窗"""# 创建弹窗alarm_window = tk.Toplevel(self.root)alarm_window.title("Alarm Settings")alarm_window.geometry("400x300")alarm_window.configure(bg='#2E2E2E')alarm_window.transient(self.root)# 创建标签和输入框entries = {}for i, addr in enumerate(self.register_addresses):# 地址标签addr_label = tk.Label(alarm_window,text=f"Address {addr}",font=('Arial', 10),bg='#2E2E2E',fg='white')addr_label.grid(row=i, column=0, padx=10, pady=5, sticky='w')# 下限输入lower_frame = tk.Frame(alarm_window, bg='#2E2E2E')lower_frame.grid(row=i, column=1, padx=5, pady=5)lower_label = tk.Label(lower_frame,text="Lower:",font=('Arial', 8),bg='#2E2E2E',fg='white')lower_label.pack(side=tk.LEFT)lower_entry = tk.Entry(lower_frame, width=10)lower_entry.pack(side=tk.LEFT)lower_entry.insert(0, str(self.alarm_settings[addr]['lower']) if self.alarm_settings[addr]['lower'] != -float('inf') else '')# 上限输入upper_frame = tk.Frame(alarm_window, bg='#2E2E2E')upper_frame.grid(row=i, column=2, padx=5, pady=5)upper_label = tk.Label(upper_frame,text="Upper:",font=('Arial', 8),bg='#2E2E2E',fg='white')upper_label.pack(side=tk.LEFT)upper_entry = tk.Entry(upper_frame, width=10)upper_entry.pack(side=tk.LEFT)upper_entry.insert(0, str(self.alarm_settings[addr]['upper']) if self.alarm_settings[addr]['upper'] != float('inf') else '')entries[addr] = {'lower': lower_entry, 'upper': upper_entry}# 保存按钮def save_settings():for addr, entry in entries.items():try:lower_val = float(entry['lower'].get()) if entry['lower'].get() else -float('inf')upper_val = float(entry['upper'].get()) if entry['upper'].get() else float('inf')self.alarm_settings[addr]['lower'] = lower_valself.alarm_settings[addr]['upper'] = upper_vallogger.info(f"Alarm settings updated for {addr}: Lower={lower_val}, Upper={upper_val}")except ValueError:logger.error(f"Invalid numeric value for {addr}")# 保存报警设置到JSON文件self.save_alarm_settings()alarm_window.destroy()save_btn = tk.Button(alarm_window,text="Save",command=save_settings,font=('Arial', 10),bg='#4E4E4E',fg='white')save_btn.grid(row=len(self.register_addresses), column=1, padx=10, pady=15)# 取消按钮cancel_btn = tk.Button(alarm_window,text="Cancel",command=alarm_window.destroy,font=('Arial', 10),bg='#4E4E4E',fg='white')cancel_btn.grid(row=len(self.register_addresses), column=2, padx=10, pady=15)self.current_date = datetime.now().strftime("%Y%m%d")  # 当前日期self.current_shift = self.get_shift()  # 当前班别self.last_shift_check = time.time()  # 上次班别检查时间def get_shift(self):"""获取当前班别"""now = datetime.now()hour &

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/88984.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/88984.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

es的自定义词典和停用词

在 Elasticsearch 中,自定义词典是优化分词效果的核心手段,尤其适用于中文或专业领域的文本处理。以下是关于 ES 自定义词典的完整指南: 为什么需要自定义词典? 默认分词不足: ES 自带的分词器(如 Standard…

微算法科技技术突破:用于前馈神经网络的量子算法技术助力神经网络变革

随着量子计算和机器学习的迅猛发展,企业界正逐步迈向融合这两大领域的新时代。在这一背景下,微算法科技(NASDAQ:MLGO)成功研发出一套用于前馈神经网络的量子算法,突破了传统神经网络在训练和评估中的性能瓶颈。这一创新…

一文读懂循环神经网络(RNN)—语言模型+读取长序列数据(2)

目录 读取长序列数据 为什么需要 “读取长序列数据”? 读取长序列数据的核心方法 1. 滑动窗口(Sliding Window) 2. 分段截取(Segmentation) 3. 滚动生成(Rolling Generation) 4. 关键信息…

Oracle Virtualbox 虚拟机配置静态IP

Oracle Virtualbox 虚拟机配置静态IP VirtualBox的网卡,默认都是第一个不能自定义,后续新建的可以自定义。 新建NAT网卡、host主机模式网卡 依次点击:管理->工具->网络管理器新建host主机模式网卡 这个网卡的网段自定义,创建…

Linux RAID1 创建与配置实战指南(mdadm)

Linux RAID1 创建与配置实战指南(mdadm)一、RAID1 核心价值与实战目标RAID1(磁盘镜像) 通过数据冗余提供高可靠性:当单块硬盘损坏时,数据不丢失支持快速阵列重建读写性能略低于单盘(镜像写入开销…

MySQL数据库----函数

目录函数1,字符串函数2,数值函数3,日期函数4,流程函数函数 1,字符串函数 MySQL中内置了很多字符串函数 2,数值函数 3,日期函数 4,流程函数

1.2 vue2(组合式API)的语法结构以及外部暴露

vue2 vue3中可以写vue2的语法&#xff0c;vue2的结构像一个花盆里的根&#xff08;根组件App.vue&#xff09;&#xff0c;根上可以插上不同的枝杈和花朵&#xff08;组件&#xff09;。 组件的结构&#xff1a; // 这里写逻辑行为 <script lang"ts"> export d…

Swift 解 LeetCode 324:一步步实现摆动排序 II,掌握数组重排的节奏感

文章目录摘要描述题解答案题解代码&#xff08;Swift&#xff09;题解代码分析步骤一&#xff1a;排序数组步骤二&#xff1a;左右指针分段步骤三&#xff1a;按位置交错插入示例测试及结果示例 1示例 2示例 3&#xff08;边界情况&#xff09;时间复杂度分析空间复杂度分析总结…

使用SQLMAP的文章管理系统CMS的sql注入渗透测试

SQLMAP注入演示&#xff1a;抓包拿到Cookie:召唤sqlmap&#xff1a;sqlmap -u "http://192.168.1.99:8085/show.php?id34" --cookie "pma_langzh_CN; kbqug_admin_username2621-PL_LxhFjyVe43ZuQvht6MI5q0ZcpRVV5FI0pzQ6XR8; kbqug_siteid2621-PL_LxhFjyVe4yA5…

I3C通信协议核心详解

一、物理层与电气特性双线结构 SCL&#xff08;串行时钟线&#xff09;&#xff1a;主设备控制&#xff0c;支持 推挽&#xff08;Push-Pull&#xff09;输出&#xff08;高速模式&#xff09;和 开漏&#xff08;Open-Drain&#xff09;&#xff08;兼容I2C模式&#xff09;。…

Docker搭建Redis哨兵集群

Redis提供了哨兵机制实现主从集群下的故障转移&#xff0c;其中包含了对主从服务的检测、自动故障恢复和通知。 1.环境 centos7、redis6.2.4、MobaXterm 目的&#xff1a; 搭建redis的主从同步哨兵集群&#xff08;一主一从三哨兵&#xff09; 2.步骤 1.主从集群的搭建 主从…

暑假Python基础整理 --异常处理及程序调试

异常概念 在程序运行过程中&#xff0c;经常会遇到各种各样的错误&#xff0c;这些错误统称为“异常”。如下表是Python常见的异常与描述&#xff1a; 异常描述NameError尝试访问一个未声明的变量引发错误IndexError索引超出序列范围引发错误IndentationError缩进错误ValueErr…

k8s-高级调度(二)

目录 Taint(污点)与Toleration(容忍) Taint&#xff08;污点&#xff09;&#xff1a;节点的排斥标记 Toleration&#xff08;容忍&#xff09;&#xff1a;Pod的适配声明 与节点亲和性的对比 警戒(cordon)和转移(drain) Cordon&#xff1a;节点隔离&#xff08;阻止新 Po…

基于OpenCV的深度学习人脸识别系统开发全攻略(DNN+FaceNet核心技术选型)

核心技术选型表 技术组件版本/型号用途OpenCV DNN4.5.5人脸检测FaceNet (facenet-pytorch)0.5.0人脸特征提取MiniConda最新版Python环境管理PyTorch1.8.0FaceNet运行基础OpenVINO2021.4模型加速(可选)SSD Caffe模型res10_300x300高精度人脸检测 一、环境准备与项目搭建 1.1 M…

【AI News | 20250714】每日AI进展

AI Repos 1、All-Model-Chat All Model Chat 是一款为Google Gemini API家族设计的网页聊天应用&#xff0c;支持多模态输入&#xff08;图片、音频、PDF等&#xff09;和多种模型&#xff08;如Gemini Flash、Imagen&#xff09;。它提供了丰富的自定义功能&#xff0c;包括高…

C 语言(二)

主要包括变量与常量、数据类型、存储方式、数制转换以及字符处理等内容一、变量与常量在 C 语言中&#xff0c;变量是用来存储数据的命名空间&#xff0c;它会在内存中分配地址。例如&#xff1a;int i; i 12345; 其中 i 是变量&#xff0c;12345 是常量。常量表示在程序运行过…

原型继承(prototypal inheritance)的工作原理

这是一个非常常见的 JavaScript 问题。所有 JS 对象都有一个__proto__属性&#xff0c;指向它的原型对象。当试图访问一个对象的属性时&#xff0c;如果没有在该对象上找到&#xff0c;它还会搜寻该对象的原型&#xff0c;以及该对象的原型的原型&#xff0c;依次层层向上搜索&…

OpenCV 视频处理与摄像头操作详解

1. 引言大家都来写OpenCV&#x1f60a;&#xff0c;学的好开心&#xff01;2. 视频基础与OpenCV简介2.1 视频的定义视频&#xff08;Video&#xff09;是由一系列静态图像&#xff08;帧&#xff09;以一定速率连续播放形成的动态影像。其本质是利用人眼的视觉暂留效应&#xf…

Agentic AI 的威胁与缓解措施

原文&#xff1a;https://www.aigl.blog/content/files/2025/04/Agentic-AI—Threats-and-Mitigations.pdf AI Agent 的定义 1. 定义与基础 智能代理&#xff08;Agent&#xff09;的定义&#xff1a; 智能代理是一种能够感知环境、进行推理、做出决策并自主采取行动以实现特定…

ArrayList列表解析

ArrayList集合 ArrayList 的底层是数组队列&#xff0c;相当于动态数组。与 Java 中的数组相比&#xff0c;它的容量能动态增长。在添加大量元素前&#xff0c;应用程序可以使用ensureCapacity操作来增加 ArrayList 实例的容量。这可以减少递增式再分配的数量。 ArrayList 继承…