You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Windows 10下监听WAV播放联动Arduino LED视觉告警方案咨询

可行方案汇总

方案一:Python脚本监控进程文件句柄 + Arduino串口通信

这是最易上手的方案,适合快速实现需求:

  1. 环境准备

    • 安装依赖库:pip install psutil pyserial
    • 确定目标程序的进程名(比如AlarmPlayer.exe),以及4个WAV文件的完整路径
  2. 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)  # 调整检测间隔
    
  3. 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发送指令:

  1. PowerShell脚本示例
    $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)
    
    注意:运行该脚本需要管理员权限,且需确保WMI服务正常运行。

方案三:API钩子拦截音频播放函数(进阶)

如果目标程序将WAV文件加载到内存播放(psutil无法检测到打开的文件),可以用钩子工具拦截音频播放API获取文件名:

  1. 工具选择:使用EasyHook(开源钩子库),编写C#或C++程序
  2. 拦截目标:拦截waveOutOpen(Windows多媒体API)或目标程序自身的播放函数,获取传入的WAV文件名
  3. 实现逻辑:钩子程序注入到目标进程,当播放函数被调用时提取文件名,通过串口发送给Arduino
  4. 优势:能精准捕获播放事件,不受文件加载方式影响;缺点是需要一定的编程基础。

内容的提问来源于stack exchange,提问作者dbnoob

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 08:06:16