ライフログという言葉をご存知でしょうか。生活の記録ということみたいですがその記録から自分の生活を振り返り改善していくが目的なんだと認識しています。過去には以下記事の睡眠中の動画記録も実施しました。
RaspberryPi3とPythonで就寝中の自分の音声付き動画をmp4で保存する
今回は新たなライフログとして自分の在宅状況を可視化する試みを行いました。
目指す姿
RaspberryPi内に在宅時と不在時の日時を記したログを記録します。
ここで在宅の定義はRaspberryPiとスマホがBluetoothの接続範囲内に
あることとしています。
基本的にスマホは常備するのでスマホが接続範囲内= 在宅という理屈です。
また、自動でログを撮り続けたいため初期設定(ペアリング)以降はRaspberryPi、スマホともに操作を必要としないことを要件としました。
BLE在宅検知のイメージ図
世の中の動向
いわゆる屋内測定と呼ばれるものは巷で溢れかえっています。
その中でも定番なのがBluetooth Low Energy(BLE)ビーコンだと思います。
事例としては会社の出退勤の打刻自動化というのがあり、
会社の入口にビーコンを設置して、社員のスマホでビーコンからの信号を
受信したら打刻時間をクラウドで記録するというものがありました。
この場合、BLEとクラウドの両方を使用していたのですがBLEだけで完結できないものかと思っていました。(結論としてはBLEだけで完結できそうです)
BLEの前提知識
最初はスマホをビーコンにしてRaspberryPiで受信すればいいではないかと考えたのですが、実はスマホ側から"バックグラウンド"、つまりはユーザーの操作無しでビーコン機能を使用することは困難であることが分かりました。
iBeaconの公式ドキュメント P11に下記の通り示されています。
Q: Can I use an iOS device to issue iBeacon advertisements while my app is in the background?
A: No. For an iOS device to issue iBeacon advertisements , the app requesting this functionality must be frontmost, with the screen turned on and the device unlocked.
iBeaconをバックグラウンドでアドバタイズメント(周りの機器に広告すること)はできないとされています。おそらく電力消耗を防いだり、ユーザの知らぬ間に
情報が外に送信され続けることを避けるためなんだと思います。
なので世の中ではビーコン専用の機器が使われています。スマホやタブレットをビーコンとして使った事例もありますが、これはビーコン機能のみに特化した使い方をしているようです。今回の場合、毎回スマホからビーコンアプリを立ち上げるのは実用的で無いと判断しました。
やり方
ではどうやるかという事ですが、BLEは使いますが、ビーコンは使いません。BLEのトポロジー(通信形態)にはコネクション型とブロードキャスト型があり、今回はコネクション型を使います。トポロジーについては下記の記事に分かりやすい説明がありました。
https://pe-bank.jp/anket/column/theme/iot_things/20170313
コネクション型は双方向通信、ブロードキャスト型は一方向通信でビーコンは送るだけの機能なのでブロードキャスト型となります。
(環境)
RaspberryPi 3 Rasbian 9.9 stretch
Python 3.5.3
スマホ 機種:SH-M04A OS:Android 6.0.1
(0) pyBlueZのインストール
下記の記事等を参考にRaspberryPiにインストールしておきます。
http://www.mizutan.com/wordpress/?p=7100
(1) ペアリング
検出したいスマホとのペアリングは手動で行います。やり方は下記の別記事に書いてます。
RaspberryPi3とAndroidスマホをコマンドラインを使わずBLEペアリングする方法図解
(2) BLE接続ログ取得プログラム作成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
#coding: utf-8 import subprocess import csv import datetime from time import sleep import RPi.GPIO as GPIO record_file_name = 'blt_detect.csv' bltcount = 0 GPIO.setmode(GPIO.BCM) GPIO.setup(21,GPIO.OUT) #物理ピン40 BCM=21 try: while True: #時刻取得 record_datetime = datetime.datetime.now() record_time = record_datetime.strftime('%Y%m%d-%X') cmd = 'hcitool con' res = subprocess.check_output(cmd.split()) print(res) #検出するスマホのアドレス bd = '00:11:22:33:44:55' #応答にスマホのアドレスが含まれているか? if(bd in res.decode()): bltcount += 1 GPIO.output(21,GPIO.HIGH) #5回連続で受信したら記録 if(bltcount == 5): print(record_time + ' ' + bd) #record_date writer = csv.writer(open(record_file_name,'a')) writer.writerow([record_time,bd,1]) bltcount = 0 else: pass else: p1 = subprocess.Popen(["echo","connect",bd], stdout=subprocess.PIPE) p2 = subprocess.Popen(["bluetoothctl"], stdin=p1.stdout, stdout=subprocess.PIPE) p1.stdout.close() outs,errs = p2.communicate() print('Attempt to connect...') bltcount = 0 GPIO.output(21,GPIO.LOW) #record_date writer = csv.writer(open(record_file_name,'a')) writer.writerow([record_time,bd,0]) sleep(6) except KeyboardInterrupt: pass |
7行目:
「blt_detect_csv」にペアリング済みのスマホを検出したログを書き込みます。
17行目:
subprocessを使って「hcitool con」コマンドを送り、応答結果をresに代入します。
21行目:
bdにスマホのアドレスを代入しておきます。サンプルでは00:11:22:33:44:55としていますが、スマホ毎に固有の数字となります。
もし不明の場合には、ターミナルを起動して
$hcitool con
と打つと、ペアリング済みのデバイスの応答が返ってくるのでそこから
確認します。((1)ペアリングの記事に図を載せています)
24〜35行目:
今回のサンプルではPi3から6秒毎(49行目のsleepで設定)にBLE接続を確認しており、応答が5回連続で取得できたらログに検出結果に '1' を書き込みます。
37〜49行目:
24行目で応答にスマホのアドレスが含まれているか、つまりPi3とスマホがBLE接続状態であるかを確認しています。スマホを持って外出するとBLE接続が
切れてしまうので、再び在宅となった際に接続する処理を行います。
ターミナルから再接続するコマンドは以下の通り
1 |
echo connect 00:11:22:33:44:55 | bluetoothctl |
なので、これをPythonのsubprocessでパイプ処理を実行します。
また応答が無い場合にはログに '0' を書き込んでいます。
(3)実行結果
Pythonのシェル画面には以下のようになります。
5回連続で応答受信したらログ書き込み、応答なしの際には接続試行を
繰り返しています。
(4)ログのグラフ表示
jupyterNotebookでグラフ表示します。
x軸は時間で1時間毎のラベルとなっており、y軸が1の時に在宅、0の時に不在となっています。
今回のサンプルではBLEの応答有無のみのログとなりましたが、今後は受信電波強度(RSSI値)等を使ったログの出力から1Fと2Fの在室分離といった事にも取り組みたいと思います。
以上。