起因:有一台设备需要监听某软件的消息,并及时回复,如果只有一个人办公时,难免有走开的情况,如何在不走远的情况下能监听到这个软件的消息,并给我提醒呢。
设计了一个最简单的方案:电脑麦克风监听声音,如果有声音发出,就向微信公众号发出一条消息
环境:Windows 10
语言:Python
应用程序:IEDA
参考文档:
python获取电脑扬声器是否在发出声音_mob649e81597922的技术博客_51CTO博客
【精选】python3 实现公众号自动发消息_python对接微信发订阅消息_XMYX-0的博客-CSDN博客
Python PyInstaller 模块使用详解(将Python程序制作成可直接运行的 EXE 程序)
一.预览
先给大家看看最后的成品:
功能很简单,代码也很简单,可以调整监听的声音阈值,超过阈值就会发消息提醒


二.配置Python环境
第一步:
打开IDEA,安装Python插件

第二步:
新建python项目


这里的Virtualenv就是虚拟环境的意思,这里的python环境与本机安装的是隔离的,方便可以使用不同的python版本和环境,所以第三方的库也需要重新安装
第三步:
安装第三方库:
启动终端,使用pip安装就可以

因为国内网络环境原因,第三方库经常下载超时,需要更换源
python程序中文件顶部有 import 方式导入第三方库,如果缺失,请使用 pip install 先安装
例如安装网络请求库 requests:pip install requests
第四步:
编写程序

右键创建python文件就可以开始编写了。
三.公众号准备
1.获取测试公众号
直接使用测试公众号,进入微信公众平台,微信扫码登录后,就可获取到测试公众号的相关信息和相关的接口文档。

2.关注测试公众号并创建消息模板
使用自己的微信关注测试公众号,可以获取到已关注的微信好的id

编辑消息模板也非常简单,有一点需要注意,模板中需要展示自定义的参数的话,需要以".DATA"结尾:
因为我这里只展示消息的时间,则定义内容是{{time.DATA}}

页面下面有模板消息的文档,可以参考官方样式

我的消息格式是这样的:
            
            
              lua
              
              
            
          
          {
  "touser": touser,
  "template_id": self.template_id,
  "topcolor": "#FF0000",
  "data": {
    "time": {
      "value": time,
      "color": "#173177"
    }
  }
}
        四.微信发送消息程序
微信公众号实现消息发送功能
直接贴代码
            
            
              python
              
              
            
          
          # encoding: utf-8
import json
import requests
class AccessToken(object):
    # 微信公众测试号账号(填写自己的)
    APPID = "wx..........."
    # 微信公众测试号密钥(填写自己的)
    APPSECRET = "2e........"
    def __init__(self, app_id=APPID, app_secret=APPSECRET) -> None:
        self.app_id = app_id
        self.app_secret = app_secret
    def get_access_token(self) -> str:
        """
        获取access_token凭证
        :return: access_token
        """
        url = f"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={self.app_id}&secret={self.app_secret}"
        resp = requests.get(url)
        result = resp.json()
        if 'access_token' in result:
            return result["access_token"]
        else:
            print(result)
class SendMessage(object):
    # 消息接收者
    TROUSER = 'od1.........', 'od1.........'
    # 消息模板id
    TEMPLATE_ID = '_BG..........'
    def __init__(self, touser=TROUSER, template_id=TEMPLATE_ID) -> None:
        """
        构造函数
        :param touser: 消息接收者
        :param template_id: 消息模板id
        """
        self.access_token = AccessToken().get_access_token()
        self.trouser = touser
        self.template_id = template_id
    def send_message(self, time) -> None:
        """
        发送消息
        :param time: 时间
        :return:
        """
        # 模板消息请求地址
        url = f"https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={self.access_token}"
        for Recipient in self.trouser:
            if Recipient != '':
                data = json.dumps(self.get_send_data(time, Recipient))
                response = requests.post(url, data=data)
                print(response.text)
    def get_send_data(self, time, touser) -> object:
        """
        获取发送消息data
        :param time: 时间
        :return: 发送的消息体
        """
        return {
            "touser": touser,
            "template_id": self.template_id,
            "topcolor": "#FF0000",
            # json数据对应模板
            "data": {
                "time": {
                    "value": time,
                    "color": "#173177"
                }
            }
        }
        流程大概就是:初始化的时候,使用appID和appsecret获取获取accessToken;然后使用accessToke和用户的微信号发送消息。
有以下四个地方需要改成自己的内容


注:Python这个类有个__init__方法,这个方法会在对象初始化时候调用。
五.声音监听程序
            
            
              python
              
              
            
          
          import time
from datetime import datetime
import numpy as np
import pyaudio
from SendMsg import SendMessage
class SoundListener:
    def __init__(self):
        self.sm = SendMessage()
        self.destroy = True
        self.display = False
        self.max = 500
    def startCheck(self):
        self.sound_listener()
    def isDestroy(self):
        return self.destroy
    def setAudioMax(self, maxValue):
        self.max = maxValue
        print("修改阈值:" + str(maxValue))
    def sound_listener(self):
        self.destroy = False
        CHUNK = 1024  # 每个音频块的大小
        FORMAT = pyaudio.paInt16  # 音频格式
        CHANNELS = 1  # 声道数量
        RATE = 44100  # 采样率
        p = pyaudio.PyAudio()
        stream = p.open(format=FORMAT,
                        channels=CHANNELS,
                        rate=RATE,
                        input=True,
                        frames_per_buffer=CHUNK)
        while True:
            if self.destroy:
                break
            data = np.frombuffer(stream.read(CHUNK), dtype=np.int16)
            if np.abs(data).mean() > self.max:  # 设置声音阈值
                print("声音正在发出!")
                # 在这里编写声音发出时需要执行的代码
                if not self.display:
                    self.display = True
                    # 发送消息
                    now_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
                    self.sm.send_message(now_time)
                else:
                    time.sleep(1)
            else:
                if self.display:
                    self.display = False
                    print("声音结束了!")
        stream.stop_stream()
        stream.close()
        p.terminate()
    def stop(self):
        self.destroy = True
        self.display = False
        这里使用了Python的三方库pyaudio,打开麦克风录音,并通过录音数据判断是否有声音。
六.创建UI交互
            
            
              python
              
              
            
          
          import threading
import tkinter as tk
from SoundListener import SoundListener
class CheckAudio:
    def __init__(self):
        self.sl = SoundListener()
        self.root = tk.Tk()
    def button_clicked(self):
        if not self.sl.isDestroy():
            self.root.label.config(text="未监听!")
            self.root.button.config(text="开始监听")
            threading.Thread(target=self.stopLis).start()
        else:
            self.root.label.config(text="监听中!")
            self.root.button.config(text="结束监听")
            threading.Thread(target=self.startLis).start()
    def stopLis(self):
        self.sl.stop()
    def startLis(self):
        self.sl.startCheck()
    def setAudioMax(self,v):
        self.sl.setAudioMax(float(v))
    def close_window(self):
        self.sl.stop()
        self.root.destroy()
    def start(self):
        # 创建主窗口
        root = self.root
        root.title("声音监听小程序")  # 设置窗口标题
        root.geometry("400x300")  # 设置窗口大小
        self.root.label = tk.Label(root, text="欢迎使用声音监听程序!", font=("Helvetica", 16))  # 创建标签控件
        self.root.label.pack(pady=20)
        # 创建按钮控件和回调函数
        self.root.button = tk.Button(root, text='开始监听', command=self.button_clicked)
        self.root.button.pack()
        # 添加一个 Scale 控件,默认垂直方向,步长设置为 100,长度为10000,滑动块的大小为 100,最后使用label参数文本
        sc = tk.Scale(root, from_=500, to=10000, orient=tk.HORIZONTAL, resolution=100, length=10000, sliderlength=100,
                      label="音量阈值控制", command=self.setAudioMax)
        sc.pack()
        #窗口关闭监听回调
        root.protocol("WM_DELETE_WINDOW", self.close_window)
        root.mainloop()
if __name__ == '__main__':
    CheckAudio().start()
        这里使用了Python的UI库tkinter;使用threading创建子线程,防止主线程卡死。
写好似乎就可以运行了,点击IDEA顶部的运行按钮试试看

附:打包exe
调试运行可以,但是给别人使用,最好windows下打包成exe文件。
这里使用 PyInstaller
安装PyInstaller :
pip install pyinstaller
        终端运行打包代码:
            
            
              r
              
              
            
          
          pyinstaller -F -w checkAudio.py
        生成的exe在以下路径中,也分享给需要的小伙伴使用吧!
