読者です 読者をやめる 読者になる 読者になる

RaspberryPiで家の騒音をグラフ化

赤ちゃんがいつ泣いているのかログを取りたい

f:id:cyamax:20170309173036j:plain 1日何時間泣いているのかや、
何時頃に泣くなど傾向がわかったら面白そうなのでやってみました。

用意するもの

  • RaspberryPi 2 or 3
  • USBマイク

環境準備

Elasticsearch×kibana×Fluentdのインストール

グラフ化するために以下環境を用意します cyamax.hateblo.jp

Python3のインストール

Pythonは2系と3系がありますが、今後主流になっていく3系を使います。
普通はpyenvやvenvを挟んで環境を切り替えることが多いですが、
RaspberryPi上だとうまくできなかったので、 シンプルに直接Python3系とモジュールをインストールします。

$ sudo apt-get install python3 python3-numpy python3-pyaudio

マイクデバイスの認識

こちらのサイトにマイクデバイスの設定方法が書いてあるので、参考にさせていただきました。 karaage.hatenadiary.jp

設定後以下のようにUSBデバイスが優先されていればOKだとおもいます

$ cat /proc/asound/modules
0 snd_usb_audio
1 snd_bcm2835

マイクのサンプリング周波数を確認

マイクから信号を受け取りにあたりサンプリング周波数を設定する必要があります。
マイクに合った設定をしないとエラーが出て取得できません。
サンプリング周波数はUSBマイクを一度Macに挿して
システム情報->ハードウェア->オーディオ->デバイス
USB PnP Sound Deviceの欄で確認できました。
Windowsの場合は試していませんがデバイスマネージャなどから確認できるかもしれません f:id:cyamax:20170308215921p:plain

騒音をログ化する

動作のながれ

  1. マイクからのストリーミングデータをCHUNK分(1024*2)ずつ抜き出してその中で最大振幅を配列max_dataに入れる。
  2. Thredingを使って指定時間ごとに割り込み処理(sendlog)を実行
  3. 割り込み処理では配列max_dataの平均値を計算してFluentdに送り、max_dataを初期化

Pythonでの割り込み処理はThredingモジュールで実装
Fluentdへはsubprocessでechoを使って実装

コード

# -*- coding:utf-8 -*-

import pyaudio
import numpy as np
import threading
import subprocess

max_data=[]
CHUNK=1024*2 # マイクによって変わる。上手くいかない場合色々試してください
RATE=48000 # 事前に確認したサンプリング周波数
p=pyaudio.PyAudio()

stream=p.open(format = pyaudio.paInt16,
        channels = 1,
        rate = RATE,
        frames_per_buffer = CHUNK,
        input = True,
        output = True)

def audio_trans(input):
    frames=(np.frombuffer(input,dtype="int16"))
    max_data.append(max(frames))
    return

def sendlog(): # 定期的に呼び出される
    global max_data
    if len(max_data) != 0: # 初回実行時だけ無視
        mic_ave=int(sum(max_data)/len(max_data)) # 60秒間のマイク受信音量の平均値を出す
        max_data=[]
        #print("スレッドの数: " + str(threading.activeCount())+threading.currentThread().getName()) #Thredingでプロセスが乱立しないかチェック用
        ## fluentdに最大音量値を渡す
        json = '{'+'\"mic_max\":{0}'.format(mic_ave)+'}'
        cmd = "echo '" + json + "' | /usr/local/bin/fluent-cat log.hoge"
        try:
            print (cmd)
            res = subprocess.check_call(cmd, shell=True )
        except:
            print ("error")
    t=threading.Timer(60,sendlog) #60秒ごとにsendlogを実行
    t.start()

t=threading.Thread(target=sendlog)
t.start()

print ("mic on")

while stream.is_active():
    input = stream.read(CHUNK)
    input = audio_trans(input)

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

print ("Stop Streaming")

実行結果

f:id:cyamax:20170308230824p:plain 1、2時間ごと夜泣きをしてそのタイミングでグラフが上昇。
朝方を過ぎた頃に子供を移動させたのとテレビをつけたので全体的に平坦になっているわかる。

感想

マイクの受信感度やメモリ管理などまだまだ調整する箇所はありますが、
やりたいことはできた感じ。
マイクはベビーベッドに設置してましたが、
泣いたタイミングで抱っこして違う部屋であやしたりしていたので、
数値の大きさはあまり当てにならない結果になってしまいました。
※上昇タイミングだけ意味のあるデータとなった

参考サイト

Raspberry Pi 2で音声認識・音声合成してみる - karaage. [からあげ]
PyAudioの基本メモ2 音声入出力 - たけし備忘録
python - Pythonのthreading.Timerで定期的に処理を呼び出すサンプル - スタック・オーバーフロー

RaspberryPiのCPU温度、電圧、クロック数をElasticsearchに送ってグラフ化

ログの可視化

せっかくelasticsearch×kibana×fluentdの環境を構築したので、
データを入れていきます。

準備

以下の手順で環境を準備します。 cyamax.hateblo.jp

CPU温度、電圧、クロック数の取得

以下の公式?サイトに載っていました。 RPI vcgencmd usage - eLinux.org

##CPU温度
vcgencmd measure_temp
##電圧
vcgencmd measure_volts
##クロック数
vcgencmd measure_clock arm

ただしこのままではグラフ化できません。 Elasticsearch側に送る必要があります。

JSONに整形

以下のスクリプトで取得したデータを整形&Elastisearchに送信をします。
crontabなどで5分ごとの定期実行させると良い感じになります。

#!/bin/bash
#raspberryPiの情報をjsonに整形する
##CPU温度
ras_temp=`vcgencmd measure_temp      |sed -e "s/temp=//" -e "s/'C//"`
##電圧
ras_volt=`vcgencmd measure_volts     |sed -e "s/volt=//" -e "s/V//"`
##クロック数
ras_freq=`vcgencmd measure_clock arm |sed -e "s/frequency(45)=//"`

#echo $ras_temp
#echo $ras_volt
#echo $ras_freq

json_date={\"ras_temp\":$ras_temp,\"ras_volt\":$ras_volt,\"ras_freq\":$ras_freq}

echo $json_date |/usr/local/bin/fluent-cat log.hoge

kibanaを見てみる

crontabで実行するごとにデータが送られて、
以下のようにkibana側で見ることができました。 f:id:cyamax:20170308040522p:plain

電圧・クロック数が動的に変化

グラフ化して初めて知ったのですが、
RaspberryPiは入力電圧によって動作クロックが変わるようです。

私の環境ではRaspberryPiに繋いでいるUSBアダプタはiPhone用の1Aアダプタを使用し、
USBケーブルは60cmほどの長めのものを使っているので、
電圧が不安定になってしまっているのだと思います。
f:id:cyamax:20170308041814p:plain 電圧とクロックが上下していることがわかります

まとめ

RaspberryPi上でデータ収集&グラフ化までできるようになりました。
次は別センサのデータを集めてみようと思います。

参考

RPI vcgencmd usage - eLinux.org

RaspberryPiでログの見える化するよ(Elasticsearch×kibana×Fluentd)

自宅簡易サーバにRaspberryPi

RaspberryPiで収集したデータを見える化したいけど、
外部のサーバやサービスを借りるとお金かかるし、
家に本格的なサーバを立てても設備代や電気代かかる・・・。
そもそも手軽に使えたら何でも良いんだけどと思い、
そのままRaspberryPi内でログ見える化の環境を構築しました。

完成図

Elasticsearch×kibana×Fluentd で構築します。 こんな感じに様々なデータが簡単にグラフ化できました。 f:id:cyamax:20170308021150p:plain

用意したもの

RaspberryPi 2(Raspbian Jessie with PIXEL)
※ネットワークへの接続やapt-get updateなど最低限のセッティングは完了しているものとする

注意

RaspberryPiはそのコンセプトから安定稼働する作りではありません。
ちょっとした学習や研究用にサーバを立てたいときは便利ですが、
中期以上の継続的な稼働が必要な場合はちゃんとサーバを用意しましょう。

Elasticsearch

Javaの確認

OSがRaspbian Jessieであれば、Javaがインストールされているはずですが一応確認。

$ java -version
java version "1.8.0_65"
Java(TM) SE Runtime Environment (build 1.8.0_65-b17)
Java HotSpot(TM) Client VM (build 25.65-b01, mixed mode)

バージョン1.8以上が必要なので、古ければアップデートしましょう。

Elasticsearchのインストール

Elasticsearchとkibanaはバージョンの組み合わせによっては動かないことがあるようなので、
今回は動作が確認されている以下バージョンでやります。

  • Elasticsearch 2.4.1
  • kibana 4.6.2

以下コマンドで、Elasticsearchの公式HPからzipをダウンロードし、
ディレクトリに展開していきます。

$ wget https://download.elastic.co/elasticsearch/release/org/elasticsearch/distribution/zip/elasticsearch/2.4.1/elasticsearch-2.4.1.zip
$ unzip elasticsearch-2.4.1.zip
$ rm elasticsearch-2.4.1.zip
$ mv elasticsearch-2.4.1 elasticsearch
$ cd elasticsearch
$ ./bin/elasticsearch

起動確認は以下コマンド。
curlすると返ってきます。

$ curl -XGET http://localhost:9200/
{
  "name" : "Micro",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "",
  "version" : {
    "number" : "2.4.1",
    "build_hash" : "",
    "build_timestamp" : "2016-09-27T18:57:55Z",
    "build_snapshot" : false,
    "lucene_version" : "5.5.2"
  },
  "tagline" : "You Know, for Search"
}

kibana

同様にkibana(4.6.2)を公式ページからダウンロードします。
以下URLからRaspberry Piのバージョンに合わせてダウンロードしてください。
RaspberryPi 2の場合:LINUX 32-BIT
RaspberryPi 3の場合:LINUX 64-BIT
https://www.elastic.co/downloads/past-releases/kibana-4-6-2

以下wgetコマンドはRaspberryPi2(32bit版)の場合

$ wget https://download.elastic.co/kibana/kibana/kibana-4.6.2-linux-x86.tar.gz
$ tar xvfz kibana-4.6.2-linux-x86.tar.gz
$ rm kibana-4.6.2-linux-x86.tar.gz
$ mv kibana-4.6.2-linux-x86 kibana
$ cd kibana
$ ./bin/kibana

しかし実行するとエラーが出ます。

./kibana/bin/../node/bin/node: 1: ./kibana/bin/../node/bin/node: Syntax error: "(" unexpected

これはダウンロードしたkibanaのファイルがRaspberryPiのCPU(ARM)アーキテクチャではないためです。
エラーが出るnodeとnpmをRaspberryPiのものに変更してあげます。
※kibanaのダウンロードページでDEBのパッケージもダウンロードできますが、
これも中身がi386アーキテクチャ用なのでdpkgでインストールできません。

$ wget http://node-arm.herokuapp.com/node_latest_armhf.deb
$ sudo apt-get remove npm node
$ sudo dpkg -i node_latest_armhf.deb
$ rm node_latest_armhf.deb
$ cd kibana/node/bin
$ mv node node.orig
$ mv npm npm.orig
$ ln -s `which node` node
$ ln -s `which npm` npm
$ cd ../../
$ ./bin/kibana

これでhttp://localhost:5601にアクセスするとkibanaのページが表示されます。

fluentd

fluentdはelasticsearchにデータを集めるために使用します。

fluentdのインストール

# インストールから設定まで
$ sudo apt-get install gem
$ sudo gem install fluentd --no-ri --no-rdoc
$ sudo fluent-gem install fluent-plugin-elasticsearch
$ fluentd --setup ./fluent

# 起動とテスト
$ fluentd -c ./fluent/fluent.conf -vv &
$ echo '{"json":"message"}' | fluent-cat debug.test

debug.test: {“json”:“message”} OKのような応答があれば初期設定は完了です。

fluentdの設定ファイル

fluentdに来たログをElasticsearchに飛ばす設定をします。
※fluentdを理解していないので、動作はしますが適切でない可能性が高いです。参考程度に見てください。

vim ~/fluent/fluent.conf

するとデフォルトの設定値が書いてありますが、
それを以下の内容にしてElasticsearchに飛ぶようにします。

<source>
    type forward
</source>

<match log.**>
    @type elasticsearch
    host localhost
    port 9200
    type_name raps
    logstash_format true
</match>

この設定を保存してfluentdを再起動するとfluentd→elasticsearchにデータが飛ぶようになりました。

ログは以下のように書くと飛ばせます。

echo '{"status":"OK"}' |/usr/local/bin/fluent-cat log.hoge

まとめ

今回はRaspberryPiにElasticsearch×kibana×Fluentdを入れてログの見える化をしました。
ただラズパイは安定稼働しないので限定的な用途に限られると思いますが、それでも簡単に自宅サーバが作れるのは便利です。

次回は
RaspberryPiのCPU温度、電圧、クロック数をElasticsearchに送る方法と
Supervisorを用いたデーモン化をやります。

参考

参考にさせていただきました。ありがとうございます。
Raspberry Pi 3にElasticsearchとKibanaをいれてみた - johshisha’s diary
ElasticSearchの良く使うcurlコマンドまとめ - サナギわさわさ.json
Elasticsearch触ってみた。 - Qiita
fluentd最低限のメモ - Qiita