9
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

INTECAdvent Calendar 2021

Day 15

ラズパイでチャイム検知してみた Part2

Last updated at Posted at 2021-12-15

はじめに

上記記事の続きになります。
前回はPyAudioを使ってチャイム音を取得し、取得した音声データをFFTして特徴を出しました。
今回はFFT後の値が閾値を超えたときに、LINEに通知を送る実装を行ったので記事を書きます。

LINEへの通知方法

LINE Notifyを使用します。
使い方は簡単で、まず通知先を設定して、アクセストークンを発行します。
アクセストークンとメッセージ内容を付与して、URLにリクエストすると設定した通知先にメッセージが送信されます。

実装

前回のプログラムを元に処理を追加しました。

.py
import numpy as np
import requests
import pyaudio
import matplotlib.pyplot as plt
from scipy.fftpack import fft

# 設定値
FORMAT      = pyaudio.paInt16
CHANNELS    = 1                 # マイクのチャンネル数
RATE        = 48000             # マイクのサンプリングレート
CHUNK       = 1024
IDINDEX     = 23                # マイクのindex
DATA_LENGTH = 1000              # 格納するデータ数


# メイン処理
def main():
    # 変数
    y = []

    # マイクの設定
    audio = pyaudio.PyAudio()
    stream = audio.open(
         format = FORMAT
        ,channels = CHANNELS
        ,rate = RATE
        ,frames_per_buffer=CHUNK
        ,input=True
        ,output=False
    )

    while stream.is_active():
        try:
            # 音声データの取得
            input = stream.read(CHUNK, exception_on_overflow=False)
            ndarray = np.frombuffer(input, dtype='int16')
            for i in ndarray:
                data = i.item()                     # 音声データの取得
                append_arr(y, data, DATA_LENGTH)    # 音声データを配列に格納

            # FFT
            freq = np.linspace(0, RATE, DATA_LENGTH)
            yf = np.abs(fft(y))
            yf = yf * yf
            
            # 判定(1000Hzの値が閾値を超えた場合通知する)
            if len(yf) == DATA_LENGTH:
                if yf[22] > 100000000000:
                    send_line_notify('チャイムがなったぞ!')

        except KeyboardInterrupt:
            break

    # plt.plot(freq[0:int(DATA_LENGTH/2)], yf[0:int(DATA_LENGTH/2)])
    # plt.show()

    stream.stop_stream()
    stream.close()
    stream.terminate()


# 配列へのデータ追加(配列数がlengthを超えた場合古いデータを削除)
def append_arr(arr, data, length):
    arr.append(data)
    while len(arr)>length:
        arr.pop(0)


# ラインに通知
def send_line_notify(notification_message):
    line_notify_token = '{LINE Notifyのアクセストークン}'
    line_notify_api = 'https://notify-api.line.me/api/notify'
    headers = {'Authorization': f'Bearer {line_notify_token}'}
    data = {'message': f'message: {notification_message}'}
    requests.post(line_notify_api, headers = headers, data = data)


if __name__ == "__main__":
    main()

上記プログラムは、1000Hz音声を取得したときLINEに通知を送る仕組みになっています。
閾値を修正することで他の特徴を持つ音声も検知することができます。
※連続でLINE通知されるなど修正すべきところがいくつかありますので、ご注意ください

↓音声検知後のライン通知
B8580B06-E333-48D5-B0AA-256A19BE973D.png

さいごに

LINE Notifyが予想以上に使いやすかったです。
通知部分のみであれば10分くらいで実装できます。
システム監視等の通知にも使えるかもですね!

9
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?