python写的 久坐站立提醒小工具

平时上班敲代码一干就是一天,久坐实在对健康不利:然而一旦干起活来要么是忘了要么就是懒了,很难及时站起来活动。。。试着找了下没找到合用的工具,故而自己做个简单的,核心思想就是简洁、简单、简朴。

网盘自取:https://pan.quark.cn/s/b148d6e85fdf

来自人民日报对久坐的提醒
在这里插入图片描述

工具使用:双击Reminder.exe即可启动
在这里插入图片描述
在这里插入图片描述
工具很小巧运行不占用内存
在这里插入图片描述
在这里插入图片描述
久坐到点提醒
在这里插入图片描述

这段代码被你改的出现问题了,帮我检查 import tkinter as tk from tkinter import ttk, filedialog, messagebox from datetime import datetime, timedelta import os import re # ============================= # 获取日志时间范围(用于 GUI 初始化等) # ============================= def get_log_time_range(log_file): min_time = None max_time = None try: with open(log_file, 'r', encoding='utf-8') as file: for line in file: line = line.strip() if not line: continue match = re.match(r'^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})', line) if not match: continue time_str = match.group(1) try: log_time = datetime.strptime(time_str, '%Y-%m-%d %H:%M:%S') if min_time is None or log_time < min_time: min_time = log_time if max_time is None or log_time > max_time: max_time = log_time except ValueError: continue except Exception as e: messagebox.showerror("错误", f"读取日志时间范围失败:\n{e}") return None, None return min_time, max_time # ============================= # 按时间和关键词过滤日志(原“日志翻译”功能) # ============================= def filter_logs_by_time_and_keywords(log_file, start_time, end_time, keyword_dict): matched_logs = [] try: start_dt = datetime.strptime(start_time, '%Y-%m-%d %H:%M:%S') end_dt = datetime.strptime(end_time, '%Y-%m-%d %H:%M:%S') except ValueError as e: messagebox.showerror("错误", f"时间格式解析失败: {e}") return matched_logs if not os.path.exists(log_file): messagebox.showerror("错误", "未找到指定的日志文件") return matched_logs try: with open(log_file, 'r', encoding='utf-8') as file: for line in file: line = line.strip() if not line: continue match = re.match(r'^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})', line) if not match: continue time_str = match.group(1) try: log_time = datetime.strptime(time_str, '%Y-%m-%d %H:%M:%S') if start_dt <= log_time <= end_dt: for keyword, description in keyword_dict.items(): if keyword in line: log_info = f"{time_str},{description},{line}" matched_logs.append(log_info) break except ValueError: continue except Exception as e: messagebox.showerror("读取错误", f"读取日志文件时出错:\n{e}") return matched_logs # ============================= # 加载 Keywords.txt 映射表 # ============================= def load_keywords(): keyword_dict = {} keywords_file = 'Keywords.txt' if not os.path.exists(keywords_file): messagebox.showwarning("警告", f"未找到 {keywords_file} 文件,将使用空关键词表。") return keyword_dict try: with open(keywords_file, 'r', encoding='utf-8') as f: for line in f: line = line.strip() if line and '|||' in line: keyword, desc = line.split('|||', 1) keyword_dict[keyword.strip()] = desc.strip() except Exception as e: messagebox.showerror("错误", f"加载 Keywords.txt 失败:\n{e}") return keyword_dict # ============================= # 选择日志文件 # ============================= def select_log_file(): file_path = filedialog.askopenfilename( title="选择日志文件", filetypes=[("Text files", "*.txt"), ("Log files", "*.log"), ("All files", "*.*")] ) if file_path: log_file_entry.delete(0, tk.END) log_file_entry.insert(0, file_path) # ============================= # 执行日志翻译(按时间段 + 关键词过滤) # ============================= def run_filter(): try: start_input = f"{start_year.get()}-{start_month.get()}-{start_day.get()} {start_hour.get()}:{start_minute.get()}:{start_second.get()}" end_input = f"{end_year.get()}-{end_month.get()}-{end_day.get()} {end_hour.get()}:{end_minute.get()}:{end_second.get()}" start_dt = datetime.strptime(start_input, '%Y-%m-%d %H:%M:%S') end_dt = datetime.strptime(end_input, '%Y-%m-%d %H:%M:%S') except ValueError: messagebox.showerror("输入错误", "时间格式无效,请检查年月日是否正确。") return log_file = log_file_entry.get().strip() if not log_file or not os.path.exists(log_file): messagebox.showerror("错误", "请提供有效的日志文件路径") return min_log_time, max_log_time = get_log_time_range(log_file) if min_log_time is None or max_log_time is None: messagebox.showwarning("警告", "无法从日志中提取任何有效时间信息。") return if end_dt < min_log_time or start_dt > max_log_time: messagebox.showerror("无数据", "日志中不包含所选时间段") return keyword_dict = load_keywords() result = filter_logs_by_time_and_keywords(log_file, start_input, end_input, keyword_dict) if not result: messagebox.showinfo("提示", "没有匹配的日志记录") return input_dir = os.path.dirname(log_file) base_name = os.path.splitext(os.path.basename(log_file))[0] output_file = os.path.join(input_dir, f"{base_name}-output.txt") try: with open(output_file, 'w', encoding='utf-8') as out_file: for log in result: parts = log.split(",", 2) if len(parts) >= 3: out_file.write(f"{parts[0]},{parts[1]}\n") out_file.write(f"{parts[2]}\n") messagebox.showinfo("完成", f"过滤完成!\n共找到 {len(result)} 条匹配日志\n已保存至:\n{output_file}") except Exception as e: messagebox.showerror("保存失败", f"无法保存文件:\n{e}") # =================================================== # 【新增】分析久坐提醒未触发的原因 # =================================================== def analyze_longsit_issues(log_file, question_file_handle): """ 分析久坐提醒相关的行为逻辑,并将每条结论+原始日志入报告 使用直接入方式,避免使用 findings 列表 """ if not os.path.exists(log_file): return timestamp_pattern = r'^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})' time_format = '%Y-%m-%d %H:%M:%S' logs_with_time = [] # (datetime, line) try: with open(log_file, 'r', encoding='utf-8') as f: for line in f: line = line.strip() if not line: continue match = re.match(timestamp_pattern, line) if match: try: dt = datetime.strptime(match.group(1), time_format) logs_with_time.append((dt, line)) except ValueError: continue except Exception as e: messagebox.showerror("读取错误", f"读取日志失败:\n{e}") return # 提取所有与久坐相关的日志 longsit_logs = [ item for item in logs_with_time if 'motion_longsit' in item[1] or 'motion_stand' in item[1] ] if len(longsit_logs) == 0: question_file_handle.write("\n\n🧩【久坐提醒分析】\n") question_file_handle.write("⚠️ 未找到任何与久坐相关的日志(motion_longsit / motion_stand),无法分析。\n") return question_file_handle.write("\n\n🧩【久坐提醒分析】\n") i = 0 while i < len(longsit_logs): dt, line = longsit_logs[i] time_str = dt.strftime('%H:%M:%S') # ① 佩戴异常 → 计时清零 if 'Wear not on Wrist or the watch is charging' in line: question_file_handle.write(f"• {time_str} 出现佩戴异常:手表未佩戴或正在充电 → 久坐计时清零\n") question_file_handle.write(f" 📜 原始日志: {line}\n") # ② 检测到站立 → 打断 elif 'motion_longsit:detect stand' in line: question_file_handle.write(f"• {time_str} 检测到用户站立久坐被打断\n") question_file_handle.write(f" 📜 原始日志: {line}\n") # ③ 中高活动量打断 elif 'current status is STANDING_STATUS type:3' in line: question_file_handle.write(f"• {time_str} 检测到中高强度活动 → 自动打断久坐\n") question_file_handle.write(f" 📜 原始日志: {line}\n") # ④ 达到久坐阈值但未提醒? elif 'motion_longsit:Motion long sit time ' in line: match_time = re.search(r'motion long sit time (\d+)', line) if not match_time: i += 1 continue duration = int(match_time.group(1)) if duration >= 60: has_walking_suspect = False has_remind_triggered = False suspect_line = None remind_line = None j = i + 1 look_ahead = 0 while j < len(longsit_logs) and look_ahead < 20: next_dt, next_line = longsit_logs[j] # 走路嫌疑判定 if 'motion_longsit: suspect walking, statusCount =' in next_line: count_match = re.search(r'statusCount = (\d+)', next_line) if count_match and int(count_match.group(1)) > 10: has_walking_suspect = True suspect_line = next_line # 是否触发提醒 if ('need to stand remind' in next_line or 'Motion remind report long sit' in next_line): has_remind_triggered = True remind_line = next_line j += 1 look_ahead += 1 # 输出判断结果 + 日志证据 if has_walking_suspect and suspect_line: next_time = re.match(r'^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})', suspect_line).group(1)[-8:] question_file_handle.write( f"• {time_str} 达到久坐阈值({duration}s)," f"但在 {next_time} 被判定为疑似走路 → 取消提醒\n" ) question_file_handle.write(f" 🕒 触发日志: {line}\n") question_file_handle.write(f" 🚶 疑似走路: {suspect_line}\n") elif has_remind_triggered and remind_line: next_time = re.match(r'^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})', remind_line).group(1)[-8:] question_file_handle.write( f"• {time_str} 达到久坐阈值({duration}s)," f"于 {next_time} 成功触发久坐提醒\n" ) question_file_handle.write(f" 🕒 触发日志: {line}\n") question_file_handle.write(f" 🔔 提醒上报: {remind_line}\n") else: question_file_handle.write( f"• {time_str} 久坐时间已达 {duration} 秒," f"后续无‘走路嫌疑’也无‘提醒上报’记录 → ⚠️ 应触发提醒但未触发!需进一步排查\n" ) question_file_handle.write(f" 📌 当前日志: {line}\n") i += 1 # 入结果 question_file_handle.write("\n\n🧩【久坐提醒分析】\n") if findings: for finding in findings: question_file_handle.write(f"• {finding}\n") else: question_file_handle.write("✅ 未发现明显久坐提醒异常行为(但仍可能受限于日志完整性)\n") # =================================================== # 主函数:检查时间断层并生成问题报告 # =================================================== def check_time_gap_and_generate_question(log_file): if not os.path.exists(log_file): messagebox.showerror("错误", "日志文件不存在") return timestamps = [] # 存储 (datetime, raw_line) time_format = "%Y-%m-%d %H:%M:%S" try: with open(log_file, 'r', encoding='utf-8') as f: for line in f: line = line.strip() if not line: continue match = re.match(r'^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})', line) if not match: continue time_str = match.group(1) try: dt = datetime.strptime(time_str, time_format) timestamps.append((dt, line)) except ValueError: continue except Exception as e: messagebox.showerror("错误", f"读取日志文件失败:\n{e}") return if len(timestamps) < 2: messagebox.showinfo("提示", "日志中少于两条有效时间记录,无法检测断层") return # 排序确保顺序 timestamps.sort(key=lambda x: x[0]) missing_periods = [] # ⚙️ 可调参数:判定为“异常断层”的最小间隔(单位:秒) GAP_THRESHOLD = 60 for i in range(len(timestamps) - 1): current_time = timestamps[i][0] next_time = timestamps[i + 1][0] gap_seconds = (next_time - current_time).total_seconds() if gap_seconds > GAP_THRESHOLD: start_missing = current_time + timedelta(seconds=1) end_missing = next_time - timedelta(seconds=1) if start_missing <= end_missing: missing_periods.append({ 'start': start_missing, 'end': end_missing, 'gap_seconds': int(gap_seconds), 'before_log': timestamps[i][1][:100], 'after_log': timestamps[i+1][1][:100] }) # 输出文件路径 output_dir = os.path.dirname(log_file) question_file = os.path.join(output_dir, "Log_Question.txt") with open(question_file, "w", encoding="utf-8") as f: if missing_periods: f.write("该日志存在长时间无更新的时间段(超过60秒未记录日志),具体如下:\n\n") for period in missing_periods: f.write(f"⚠️ 时间断层:从 {period['start'].strftime('%Y-%m-%d %H:%M:%S')} " f"到 {period['end'].strftime('%Y-%m-%d %H:%M:%S')} " f"(共缺失 {period['gap_seconds']} 秒)\n") f.write(f" 上一条日志: {period['before_log']}\n") f.write(f" 下一条日志: {period['after_log']}\n\n") else: f.write("✅ 日志时间分布合理,无显著断层。\n\n") # =================== 调用久坐提醒分析 =================== analyze_longsit_issues(log_file, f) messagebox.showwarning( "⚠️ 分析完成", f"问题分析已完成,详情见:\n{question_file}" ) # ===================================== # 执行时间断层检测(按钮回调) # ===================================== def run_time_check(): log_file = log_file_entry.get().strip() if not log_file: messagebox.showerror("错误", "请先选择日志文件") return if not os.path.exists(log_file): messagebox.showerror("错误", "日志文件不存在,请检查路径") return check_time_gap_and_generate_question(log_file) # ============================= # 创建主窗口 # ============================= root = tk.Tk() root.title("日志分析工具") root.geometry("650x400") root.resizable(False, False) # === 当前时间初始化 === now = datetime.now() default_year = now.year default_month = now.month default_day = now.day # === 日志文件选择区域 === log_frame = ttk.Frame(root, padding="10") log_frame.pack(pady=10, fill=tk.X) ttk.Label(log_frame, text="日志文件路径:").grid(row=0, column=0, sticky=tk.W, padx=(0, 5)) log_file_entry = ttk.Entry(log_frame, width=50) log_file_entry.grid(row=0, column=1, padx=5) ttk.Button(log_frame, text="浏览...", command=select_log_file).grid(row=0, column=2, padx=(5, 0)) # === 时间选择区域 === time_frame = ttk.LabelFrame(root, text="时间范围设置", padding="10") time_frame.pack(padx=20, pady=10, fill=tk.X) row_start = 0 row_end = 1 # --- 开始时间 --- ttk.Label(time_frame, text="开始时间:").grid(row=row_start, column=0, sticky=tk.E, padx=(0, 5), pady=2) start_year = tk.StringVar(value=default_year) start_month = tk.StringVar(value=f"{default_month:02d}") start_day = tk.StringVar(value=f"{default_day:02d}") start_hour = tk.StringVar(value="00") start_minute = tk.StringVar(value="00") start_second = tk.StringVar(value="00") ttk.Spinbox(time_frame, from_=2000, to=2100, textvariable=start_year, width=6).grid(row=row_start, column=1, padx=2) ttk.Label(time_frame, text="-").grid(row=row_start, column=2) ttk.Spinbox(time_frame, from_=1, to=12, textvariable=start_month, width=4).grid(row=row_start, column=3, padx=2) ttk.Label(time_frame, text="-").grid(row=row_start, column=4) ttk.Spinbox(time_frame, from_=1, to=31, textvariable=start_day, width=4).grid(row=row_start, column=5, padx=2) ttk.Label(time_frame, text=" ").grid(row=row_start, column=6) ttk.Spinbox(time_frame, from_=0, to=23, textvariable=start_hour, width=4).grid(row=row_start, column=7, padx=2) ttk.Label(time_frame, text=":").grid(row=row_start, column=8) ttk.Spinbox(time_frame, from_=0, to=59, textvariable=start_minute, width=4).grid(row=row_start, column=9, padx=2) ttk.Label(time_frame, text=":").grid(row=row_start, column=10) ttk.Spinbox(time_frame, from_=0, to=59, textvariable=start_second, width=4).grid(row=row_start, column=11, padx=2) # --- 结束时间 --- ttk.Label(time_frame, text="结束时间:").grid(row=row_end, column=0, sticky=tk.E, padx=(0, 5), pady=2) end_year = tk.StringVar(value=default_year) end_month = tk.StringVar(value=f"{default_month:02d}") end_day = tk.StringVar(value=f"{default_day:02d}") end_hour = tk.StringVar(value="23") end_minute = tk.StringVar(value="59") end_second = tk.StringVar(value="59") ttk.Spinbox(time_frame, from_=2000, to=2100, textvariable=end_year, width=6).grid(row=row_end, column=1, padx=2) ttk.Label(time_frame, text="-").grid(row=row_end, column=2) ttk.Spinbox(time_frame, from_=1, to=12, textvariable=end_month, width=4).grid(row=row_end, column=3, padx=2) ttk.Label(time_frame, text="-").grid(row=row_end, column=4) ttk.Spinbox(time_frame, from_=1, to=31, textvariable=end_day, width=4).grid(row=row_end, column=5, padx=2) ttk.Label(time_frame, text=" ").grid(row=row_end, column=6) ttk.Spinbox(time_frame, from_=0, to=23, textvariable=end_hour, width=4).grid(row=row_end, column=7, padx=2) ttk.Label(time_frame, text=":").grid(row=row_end, column=8) ttk.Spinbox(time_frame, from_=0, to=59, textvariable=end_minute, width=4).grid(row=row_end, column=9, padx=2) ttk.Label(time_frame, text=":").grid(row=row_end, column=10) ttk.Spinbox(time_frame, from_=0, to=59, textvariable=end_second, width=4).grid(row=row_end, column=11, padx=2) # === 功能按钮 === run_button = ttk.Button(root, text="🔍 开始日志翻译", command=run_filter) run_button.pack(pady=10) check_button = ttk.Button(root, text="⏱️ 问题定位", command=run_time_check) check_button.pack(pady=5) # 启动主循环 root.mainloop()
12-06
基于可靠性评估序贯蒙特卡洛模拟法的配电网可靠性评估研究(Matlab代码实现)内容概要:本文围绕“基于可靠性评估序贯蒙特卡洛模拟法的配电网可靠性评估研究”,介绍了利用Matlab代码实现配电网可靠性的仿真分析方法。重点采用序贯蒙特卡洛模拟法对配电网进行长时间段的状态抽样与统计,通过模拟系统元件的故障与修复过程,评估配电网的关键可靠性指标,如系统停电频率、停电持续时间、负荷点可靠性等。该方法能够有效处理复杂网络结构与设备时序特性,提升评估精度,适用于含分布式电源、电动汽车等新型负荷接入的现代配电网。文中提供了完整的Matlab实现代码与案例分析,便于复现和扩展应用。; 适合人群:具备电力系统基础知识和Matlab编程能力的高校研究生、科研人员及电力行业技术人员,尤其适合从事配电网规划、运行与可靠性分析相关工作的人员; 使用场景及目标:①掌握序贯蒙特卡洛模拟法在电力系统可靠性评估中的基本原理与实现流程;②学习如何通过Matlab构建配电网仿真模型并进行状态转移模拟;③应用于含新能源接入的复杂配电网可靠性定量评估与优化设计; 阅读建议:建议结合文中提供的Matlab代码逐段调试运行,理解状态抽样、故障判断、修复逻辑及指标统计的具体实现方式,同时可扩展至不同网络结构或加入更多不确定性因素进行深化研究。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

企鹅侠客

您的打赏是我创作旅程中的关键燃

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值