【ソース公開】コロナが怖いので冷蔵庫で生存報告するシステム作った 

備忘録がてら

# 目次
1. [きっかけ](#きっかけ)
1. [構想](#構想)
1. [成果物](#成果物)
1. [買ったもの](#買ったもの)
	1. [そのほか使ったもの](#そのほか使ったもの)
1. [ラズパイのセットアップ](#ラズパイのセットアップ)
1. [電子工作](#電子工作)
1. [LINE Notifyの登録](#line-notifyの登録)
1. [開発](#開発)
    1. [システム構成](#システム構成)
    1. [プログラム](#プログラム)
    1. [システムの監視](#システムの監視)
    1. [システムの自動起動](#システムの自動起動)
1. [さいごに](#さいごに)
1. [参考サイト様](#参考サイト様)


# きっかけ
一人暮らしなので
</br>
コロナ
↓
人知れず死ぬ
</br></br>
が怖いので危篤状態の検知＋生きていることを逐次報告できるシステムを作ろうと思った。
</br>

# 構想

やりたいことは

- 自宅にセンサーを取り付けて、24時間検知
- 日常生活の動作から検知できて、システムを意識したくない
- 通信相手(両親)が使ってるアプリ→LINEに通知する

冷蔵庫であれば毎日開け閉めをするので、
冷蔵庫の扉に磁気センサーを取り付けたRaspberry Piを設置し、Python×LINE Notifyで実現する。

# 成果物
実物
![IMG_20210815_193846_886.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1873792/b8d14359-29a2-89af-12f6-bbfb0a55c61e.jpeg)

![kansei_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1873792/7af647c3-b37b-2bfc-3a56-4d9d77e23704.jpeg)

冷蔵庫を開けたときLINEの通知画面（頻繁に通知するのでLINEアプリ側で通知OFF）
![line_notifity.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1873792/b51e336c-8986-1648-24e6-a22b41273f96.png)

しばらくの間冷蔵庫の開閉がなかった時の通知(別グループ)
![line_alert.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1873792/267a54c5-bd80-6133-965a-5b73954673fc.png)

ラズパイの起動画面(システムと監視システム)
![kansei_3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1873792/d3eb30e2-6294-d8c0-1754-554c7979ff5b.png)

電子工作・Python共に初心者の割にはちゃんと動作するので目的は達成。
開発期間は１～２日程度

# 買ったもの
総額6000円ぐらい
</br>
アマゾンとヨドバシで買った。ジャンパーワイヤ等パーツ類は秋月電子通商で買ったほうがよさそう
</br>
・はんだごてセット（845円）
https://www.amazon.co.jp/gp/product/B00J7BNP5U
</br>
・microSD 32GB（780円）
https://www.amazon.co.jp/gp/product/B09379M37J
</br>
・磁気センサー（1000円）
https://www.amazon.co.jp/gp/product/B0833LJQDV
</br>
・ジャンパーワイヤ オス-メス（589円）
https://www.amazon.co.jp/gp/product/B07MR1SVVR
</br>
・Raspberry Pi Zero WH(2630円)
　GPIOを使いたかったので最初から取り付けられているZero WHを購入
https://www.yodobashi.com/product/100000001003904466/
</br>
・ヒートシンク（125円）
https://www.yodobashi.com/product/100000001003498338/
　
## そのほか使ったもの
・MicroB ACアダプタ
　Zero WHの充電用
</br>
・HDMI-MiniHDMIケーブル
　Zero WHのモニター接続用。mini-HDMIをmicro-HDMIと間違えないように
　※Zero WHはmini-HDMIで、4 Model Bはmicro-HDMI
</br>
・USB MicroB-A変換アダプタ
　Zero WHにはUSB-TypeAが無いのでキーボードやら接続するのに必要
</br>
・マウス/キーボード
　無線でマウス/キーボードセットのものが便利
</br>
・ビニールテープ
　はんだづけした箇所に巻いた（熱収縮テープのほうがいいかも）

# ラズパイのセットアップ

microSDをクリーンアップし、Raspberry Pi OSを下記リンクからダウンロード→インストール後、取り付け。
https://www.raspberrypi.org/software/
![pi_zero_WH_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1873792/0e88b586-62df-075b-f8af-f455b5d28c55.jpeg)

ヒートシンクの取り付け。
![pi_zero_WH_3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1873792/6271fdc7-641d-c5cb-584f-68a865eae93b.jpeg)

モニターと接続、電源を供給しOSの初期セットアップ。※検索すればいっぱい出てくるので省略

# 電子工作
ぶきっちょにとって一番の鬼門。学生以来のはんだごてでおっかなびっくり。

磁気センサーとジャンパーワイヤ(オス-メス)2本のオス部分とはんだづけする。
![1628493866544_1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1873792/9db64343-588d-abf3-d75e-f093d24a6629.jpeg)皿

はんだづけできたらRaspberry Pi Zero WHのGPIOボードにジャンパーワイヤのメス部分を接続する。
片方をGPIO4、もう片方はGND。
![pi_zero_WH_5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1873792/b8b80e46-053e-e757-6c4b-cb814e43a465.jpeg)
![gpio.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1873792/2820e501-fbb2-8675-7d67-c017f9c15d4b.png)

# LINE Notifyの登録
登録・トークンの取得方法は下記リンク参照。　
https://qiita.com/akeome/items/e1e0fecf2e754436afc8
</br></br>
通常通知用のグループと緊急用グループ2つを連携。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1873792/598329fc-d037-0ece-0016-01c3e81e8189.png)

# 開発
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時間ごとに再通知する。

```Python:Main.py
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:
                    #最後に警告した時間から１時間以上経過している場合                    
                    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")
```
<br>

```Python:LINENotification.py
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)
```
<br>

```Python:PrintLog.py
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')) 
```
<br>

## システムの監視
システムが停止した時に再起動するシェルスクリプトを作成。
<br>

```Bash:start.sh
#!/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」ディレクトリにデスクトップエントリを作成。

```:start.desktop
[Desktop Entry]
Exec=lxterminal -e "sh /home/「User」/Desktop/start.sh"
Type=Application
```

# さいごに
想定していたものが思いのほか簡単にできたので良かった。
</br>
現代の素晴らしい物流システムのおかげで着想から1週間程度で実現できたので、今後も何か思いついたら作っていきたい。

# 参考サイト様
[LINE Notify公式](https://notify-bot.line.me/ja/)

[ラズパイで100均ドア開閉センサー検知](https://monomonotech.jp/kurage/raspberrypi/daiso_sensorlight.html)

[ラズパイで冷蔵庫の閉め忘れをLINE通知する](https://note.com/yuzo111/n/na81a36d4a1b4)

[PythonでLINE Notifyへ通知を送る](https://qiita.com/akeome/items/e1e0fecf2e754436afc8)

[デスクトップ起動後に、自動的に指定したプログラムを起動させる方法について](https://www.raspberrypi.org/forums/viewtopic.php?t=108958)