備忘録がてら
目次
きっかけ
一人暮らしなので
コロナ
↓
人知れず死ぬ
が怖いので危篤状態の検知+生きていることを逐次報告できるシステムを作ろうと思った。
構想
やりたいことは
- 自宅にセンサーを取り付けて、24時間検知
- 日常生活の動作から検知できて、システムを意識したくない
- 通信相手(両親)が使ってるアプリ→LINEに通知する
冷蔵庫であれば毎日開け閉めをするので、
冷蔵庫の扉に磁気センサーを取り付けたRaspberry Piを設置し、Python×LINE Notifyで実現する。
成果物
冷蔵庫を開けたときLINEの通知画面(頻繁に通知するのでLINEアプリ側で通知OFF)
電子工作・Python共に初心者の割にはちゃんと動作するので目的は達成。
開発期間は1~2日程度
買ったもの
総額6000円ぐらい
アマゾンとヨドバシで買った。ジャンパーワイヤ等パーツ類は秋月電子通商で買ったほうがよさそう
・はんだごてセット(845円)
https://www.amazon.co.jp/gp/product/B00J7BNP5U
・microSD 32GB(780円)
https://www.amazon.co.jp/gp/product/B09379M37J
・磁気センサー(1000円)
https://www.amazon.co.jp/gp/product/B0833LJQDV
・ジャンパーワイヤ オス-メス(589円)
https://www.amazon.co.jp/gp/product/B07MR1SVVR
・Raspberry Pi Zero WH(2630円)
GPIOを使いたかったので最初から取り付けられているZero WHを購入
https://www.yodobashi.com/product/100000001003904466/
・ヒートシンク(125円)
https://www.yodobashi.com/product/100000001003498338/
そのほか使ったもの
・MicroB ACアダプタ
Zero WHの充電用
・HDMI-MiniHDMIケーブル
Zero WHのモニター接続用。mini-HDMIをmicro-HDMIと間違えないように
※Zero WHはmini-HDMIで、4 Model Bはmicro-HDMI
・USB MicroB-A変換アダプタ
Zero WHにはUSB-TypeAが無いのでキーボードやら接続するのに必要
・マウス/キーボード
無線でマウス/キーボードセットのものが便利
・ビニールテープ
はんだづけした箇所に巻いた(熱収縮テープのほうがいいかも)
ラズパイのセットアップ
microSDをクリーンアップし、Raspberry Pi OSを下記リンクからダウンロード→インストール後、取り付け。
https://www.raspberrypi.org/software/
モニターと接続、電源を供給しOSの初期セットアップ。※検索すればいっぱい出てくるので省略
電子工作
ぶきっちょにとって一番の鬼門。学生以来のはんだごてでおっかなびっくり。
磁気センサーとジャンパーワイヤ(オス-メス)2本のオス部分とはんだづけする。
皿
はんだづけできたらRaspberry Pi Zero WHのGPIOボードにジャンパーワイヤのメス部分を接続する。
片方をGPIO4、もう片方はGND。
LINE Notifyの登録
登録・トークンの取得方法は下記リンク参照。
https://qiita.com/akeome/items/e1e0fecf2e754436afc8
通常通知用のグループと緊急用グループ2つを連携。
開発
Raspberry Pi OSにデフォルトインストールされているThonnyで開発した。
Pythonは普段触っておらずコード量も多くないので、中身はご容赦いただきたい。
システム構成
/home/「User」/Desktop/Fridge_Open_Notification_System/
┣ log ━ 「ログファイル」
┣ Main.py ・・・メインプログラム
┣ LINENotification.py ・・・LINE Notify通知用
┗ PrintLog.py ・・・ログファイル生成用
プログラム
プログラムを起動するとコンソールが起動し、while文で磁気センサーのinput情報を取得し続ける。
磁気センサーが開くのを検知したらLINEの通知を飛ばす。
直近の通知から12時間経過したら注意用の通知、24時間経過したら警告用の通知、その後1時間ごとに再通知する。
import time
import RPi.GPIO as GPIO
import requests
import datetime
#自作関数------------------
import PrintLog
import LINENotification
#冷蔵庫開閉通知システム Main関数
Magnet_PIN = 4 #磁気センサーの刺さったGPIOのPIN番号
SW_Status = 1 #磁気センサーON/OFFステータス
IsOpened = False #冷蔵庫開放時フラグ
LastNotified = datetime.datetime.now() #直近の通知時刻
LastNotified_Warning = datetime.datetime(1999,1,1,0,0,0) #直近の警告通知時刻
AttentionHour = 12 #注意経過時間 ※直近の通知時刻から一定期間応答がなかった場合、注意する
WarningHour = 24 #警告経過時間 ※直近の通知時刻から一定期間応答がなかった場合、警告する
IsNotified_Attention = False #注意フラグ
StartHour = 6 #通知開始時間
EndHour = 22 #通知終了時間
#Magnet_PINを入力モード、pull_up設定にする
GPIO.setmode(GPIO.BCM)
GPIO.setup(Magnet_PIN,GPIO.IN,pull_up_down=GPIO.PUD_UP)
while True:
try:
SW_Status = GPIO.input(Magnet_PIN)
if SW_Status == 0:
#扉が閉まっていたら
nowDate = datetime.datetime.now()
print("Close")
#直近の通知時刻から注意経過時刻・警告経過時刻の取得
AttentionTime = LastNotified + datetime.timedelta(hours=AttentionHour)
WarningTime = LastNotified + datetime.timedelta(hours=WarningHour)
if nowDate >= WarningTime:
#直近の通知時刻から警告経過時間応答がなかった場合
LastNotified_Warning_add1hour = LastNotified_Warning + datetime.timedelta(hours=1)
if nowDate >= LastNotified_Warning_add1hour:
#最後に警告した時間から1時間以上経過している場合
LINENotification.Alert("【警告】最後の冷蔵庫開閉通知から"\
+ str(WarningHour) + "時間以上経過しました。\n"\
+ "本人に連絡をしてください。\n"\
"直近の通知時刻:" + LastNotified.strftime('%Y年%m月%d日 %H:%M:%S'))
LastNotified_Warning = nowDate
elif nowDate >= AttentionTime:
#直近の通知時刻から注意経過時間応答がなかった場合
if IsNotified_Attention == False:
LINENotification.Alert("【注意】最後の冷蔵庫開閉通知から"\
+ str(AttentionHour) + "時間経過しました。\n"\
+ "心配な場合、本人に連絡をしてみてください。\n"\
"直近の通知時刻:" + LastNotified.strftime('%Y年%m月%d日 %H:%M:%S'))
IsNotified_Attention = True
IsOpened = False
else:
#扉が開いていたら
nowDate = datetime.datetime.now()
if IsOpened == True:
continue
print("Open!")
PrintLog.func("冷蔵庫Open")
if StartHour <= nowDate.hour and nowDate.hour < EndHour:
#LINEに通知する
LINENotification.func("冷蔵庫パカッ")
else:
#通知時間外だった場合
PrintLog.func("寝る時間なので通知しないよ")
#直近の通知時刻にセット
LastNotified = nowDate
IsOpened = True
time.sleep(1)
except:
break
GPIO.cleanup()
print("end")
import requests
import os
import datetime
#LINEに通知
def func(message='テストメッセージ'):
#通知用メッセージ
message_str = message + " "+ datetime.datetime.now().strftime('%Y年%m月%d日 %H:%M:%S')
line_notify_token = '「グループのトークン」'
line_notify_api = 'https://notify-api.line.me/api/notify'
headers = {'Authorization': f'Bearer {line_notify_token}'}
data = {'message': f' {message_str}'}
requests.post(line_notify_api, headers = headers, data = data)
#警告用:LINEに通知
def Alert(message='テストメッセージ'):
line_notify_token = '「グループのトークン」'
line_notify_api = 'https://notify-api.line.me/api/notify'
headers = {'Authorization': f'Bearer {line_notify_token}'}
data = {'message': f' {message}'}
requests.post(line_notify_api, headers = headers, data = data)
import os
import datetime
#ログ生成関数
def func(message='テストメッセージ'):
print("LogWrite:" + message)
LogDir = "/home/「User」/Desktop/Fridge_Open_Notification_System/log"
LogFile = LogDir + "/" + datetime.datetime.now().strftime('%Y%m%d.txt')
#ディレクトリが存在しない場合、新規作成
if not os.path.exists(LogDir):
os.makedirs(LogDir)
#ログファイル書き込み
f = open(LogFile, 'a', encoding='UTF-8')
f.writelines(message + " " + datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S\n'))
システムの監視
システムが停止した時に再起動するシェルスクリプトを作成。
#!/bin/bash
#冷蔵庫開閉通知システムの監視
ProcessName=start.sh
echo "冷蔵庫開閉通知システムの監視"
while true
do
count=`ps -ef | grep /home/「User」/Desktop/Fridge_Open_Notification_System/Main.py | grep -v grep | wc -l`
if [ $count = 0 ]; then
#システムが停止していたら起動
echo "start:Fridge_Open_Notification_System"
lxterminal -e "python3 /home/「User」/Desktop/Fridge_Open_Notification_System/Main.py"
fi
sleep 1
done
システムの自動起動
ラズパイが停止した際、起動のためだけにいちいちモニターに接続するのも面倒なので、自動起動の設定をした。
「/home/「User」/.config/autostart」ディレクトリにデスクトップエントリを作成。
[Desktop Entry]
Exec=lxterminal -e "sh /home/「User」/Desktop/start.sh"
Type=Application
さいごに
想定していたものが思いのほか簡単にできたので良かった。
現代の素晴らしい物流システムのおかげで着想から1週間程度で実現できたので、今後も何か思いついたら作っていきたい。