Windows 10下监听WAV播放联动Arduino LED视觉告警方案咨询
可行方案汇总
方案一:Python脚本监控进程文件句柄 + Arduino串口通信
这是最易上手的方案,适合快速实现需求:
环境准备
- 安装依赖库:
pip install psutil pyserial - 确定目标程序的进程名(比如
AlarmPlayer.exe),以及4个WAV文件的完整路径
- 安装依赖库:
Python监控脚本
实时检查目标进程打开的文件,检测到对应WAV文件被使用时,向Arduino发送指令:import psutil import serial import time # 配置参数 TARGET_PROCESS = "AlarmPlayer.exe" # 替换为你的告警程序进程名 WAV_MAPPING = { "C:/alarm/warning1.wav": "R", # 红色LED指令 "C:/alarm/warning2.wav": "Y", # 黄色LED指令 "C:/alarm/warning3.wav": "G", # 绿色LED指令 "C:/alarm/warning4.wav": "B" # 蓝色LED指令 } SERIAL_PORT = "COM3" # 替换为Arduino的COM端口 BAUD_RATE = 9600 # 初始化串口 ser = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1) time.sleep(2) # 等待Arduino初始化 last_played = None while True: current_wav = None # 遍历所有进程,找到目标进程 for proc in psutil.process_iter(['name', 'open_files']): try: if proc.info['name'] == TARGET_PROCESS: # 检查进程打开的文件 for file in proc.info['open_files']: if file.path in WAV_MAPPING: current_wav = file.path break except (psutil.NoSuchProcess, psutil.AccessDenied): continue # 仅当播放的WAV文件变化时发送指令 if current_wav and current_wav != last_played: ser.write(WAV_MAPPING[current_wav].encode()) last_played = current_wav elif not current_wav and last_played: ser.write("O".encode()) # 发送关闭所有LED的指令 last_played = None time.sleep(0.5) # 调整检测间隔Arduino控制代码
接收串口指令,控制对应LED引脚:#define RED_LED 2 #define YELLOW_LED 3 #define GREEN_LED 4 #define BLUE_LED 5 void setup() { pinMode(RED_LED, OUTPUT); pinMode(YELLOW_LED, OUTPUT); pinMode(GREEN_LED, OUTPUT); pinMode(BLUE_LED, OUTPUT); Serial.begin(9600); // 初始关闭所有LED digitalWrite(RED_LED, LOW); digitalWrite(YELLOW_LED, LOW); digitalWrite(GREEN_LED, LOW); digitalWrite(BLUE_LED, LOW); } void loop() { if (Serial.available() > 0) { char cmd = Serial.read(); // 先关闭所有LED digitalWrite(RED_LED, LOW); digitalWrite(YELLOW_LED, LOW); digitalWrite(GREEN_LED, LOW); digitalWrite(BLUE_LED, LOW); // 根据指令点亮对应LED switch(cmd) { case 'R': digitalWrite(RED_LED, HIGH); break; case 'Y': digitalWrite(YELLOW_LED, HIGH); break; case 'G': digitalWrite(GREEN_LED, HIGH); break; case 'B': digitalWrite(BLUE_LED, HIGH); break; case 'O': // 关闭所有,无需额外操作 break; } } }
方案二:WMI事件监控文件访问 + PowerShell脚本
利用Windows原生WMI监控文件打开事件,触发后向Arduino发送指令:
- PowerShell脚本示例
注意:运行该脚本需要管理员权限,且需确保WMI服务正常运行。$wavPaths = @( "C:\alarm\warning1.wav", "C:\alarm\warning2.wav", "C:\alarm\warning3.wav", "C:\alarm\warning4.wav" ) $serialPort = new-Object System.IO.Ports.SerialPort COM3,9600,None,8,one $serialPort.Open() # 注册文件打开事件监控 $query = "SELECT * FROM __InstanceCreationEvent WITHIN 0.5 WHERE TargetInstance ISA 'CIM_DataFile' AND TargetInstance.Name IN ('" + ($wavPaths -join "','").Replace("\","\\") + "')" Register-WmiEvent -Query $query -Action { $wavPath = $event.SourceEventArgs.NewEvent.TargetInstance.Name switch($wavPath) { "C:\alarm\warning1.wav" { $serialPort.WriteLine("R") } "C:\alarm\warning2.wav" { $serialPort.WriteLine("Y") } "C:\alarm\warning3.wav" { $serialPort.WriteLine("G") } "C:\alarm\warning4.wav" { $serialPort.WriteLine("B") } } } # 注册文件关闭事件监控(可选,用于关闭LED) $closeQuery = "SELECT * FROM __InstanceDeletionEvent WITHIN 0.5 WHERE TargetInstance ISA 'CIM_DataFile' AND TargetInstance.Name IN ('" + ($wavPaths -join "','").Replace("\","\\") + "')" Register-WmiEvent -Query $closeQuery -Action { $serialPort.WriteLine("O") } # 保持脚本运行 do { Start-Sleep -Seconds 1 } while ($true)
方案三:API钩子拦截音频播放函数(进阶)
如果目标程序将WAV文件加载到内存播放(psutil无法检测到打开的文件),可以用钩子工具拦截音频播放API获取文件名:
- 工具选择:使用EasyHook(开源钩子库),编写C#或C++程序
- 拦截目标:拦截
waveOutOpen(Windows多媒体API)或目标程序自身的播放函数,获取传入的WAV文件名 - 实现逻辑:钩子程序注入到目标进程,当播放函数被调用时提取文件名,通过串口发送给Arduino
- 优势:能精准捕获播放事件,不受文件加载方式影响;缺点是需要一定的编程基础。
内容的提问来源于stack exchange,提问作者dbnoob
相关产品推荐
相关产品推荐

