DreamerDreamのブログ

夢想家の夢です。

サーバー停電復旧後にお知らせメールを送る

現在僕のRaspberryPiはエアコンを屋外からhttps接続で操作出来る遠隔リモコンシステムが稼働中だ。

エアコンのみではなくTVやビデオも操作出来るようにしたので屋内からスマホでTVの操作も出来るようにしてある。反応速度は遅いが割と便利に試験運用中だ。

 

部屋にいるペットが猛暑日熱中症にかかるなんて嫌だからこんなシステムを作って室温を確認してエアコン操作出来るようにした。

室温が35℃を超えたり5℃を下回ると自動でエアコン作動させて「室温異常を感知したのでエアコン稼働したよ」という旨のメールが送られて来る仕様。

この仕様では予想外の日中温度の上昇、下降に対処できる。

 

しかし朝から予想出来る暑い日にエアコンを付けて家を出たのに知らない間に停電になっていてエアコンが停まってしまったら35℃を超えるまでこのシステムではエアコン起動しない。

なのでこのシステムを作って停電時にはお知らせしてくれるようにした。停電をお知らせしてくれるだけでエアコンは入れてくれないが気が付いたら遠隔操作で早急にエアコン稼働させられる。

 

動作概要は単純

  1. デーモンkill時に起動するよう設定したアプリが起動されたら任意の場所にシステム正常終了フラグを書き出す。
  2. 起動時にシステム正常終了フラグが無ければ異常終了だと判断してメール送信。フラグがあれば正常終了と判断してフラグを削除して終了。

これだけ。

RaspberryPiは電源スイッチが無く電源投入するとすぐ起動するので停電が復旧したらすぐ起動してくれる。

気をつけるべきは立ち上がり後すぐにメールを送ろうとしてもルーターが立ち上がっていない場合があるということ。

なのでシステム起動後5分後にメールを送信する。ということにした。

本当はインターネットに接続されているかを確認した方が良いのだろうけれど・・・今後の課題とする。

 

systemdを利用するとシステム起動時と終了時に呼ぶアプリを設定出来るらしい。

Linux初心者だから設定が合っているのかよくわからないけれどいろんなサイトを見て回って、こんな感じで書いた。

--  /usr/lib/systemd/system/shutdown_checkd.service --

[Unit]
Description=Shutdown Check Daemon

[Service]
ExecStart=/usr/local/lib/shutdown_checkd.py
Restart=always
ExecStopPost=/usr/local/lib/shutdown_writed.py
Type=forking
PIDFile=/var/run/shutdown_checkd.pid

[Install]
WantedBy=multi-user.target

これでシステム起動時に 

/usr/local/lib/shutdown_checkd.py

が呼ばれ、

システム終了時に

/usr/local/lib/shutdown_writed.py

が呼ばれるようだ。

 

起動時に一度呼ばれるだけだからPIDの管理が必要かわからないけれどpid生成して管理する方法しか知らないのでバカの一つ覚えでこのようにした。

 

で、起動時に呼ばれるコードがこちら

-- /usr/local/lib/shutdown_checkd.py

 

#!/usr/bin/python

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

 

import file_mng

import gmail

import atexit, time, os, sys

 

file_path = "/usr/local/lib/shutdown.flag"

address = ["アドレス1@yahoo.co.jp","アドレス2@gmail.com"]

sub = "RaspberryPi2nd[shutdown_checkd]からのお知らせです。"

body = "起動時にlogが確認出来ませんでした。\n約5分前に停電が起きた可能性があります。\nエアコンや室温等を確認してください。\nhttps://〜〜\n"

logfilename="/usr/local/lib/shutdownlog.log"

logdaytime = " "

 

def log(logdata):

    daytime = file_mng.get_daytime()

    file_mng.save_add(logfilename,daytime + ":" + logdata + "\n")

 

def loop():

    while 1:

        time.sleep(3600)

 

def alart():

    global logdaytime

    logdaytime = "システム起動日時:" + file_mng.get_daytime()

    time.sleep(300)#ルーター等が起動完了するまで約5分待つ

    for add in address:

        gmail.send(add,sub,body + logdaytime)

        time.sleep(1)

 

def read():

    if os.path.isfile(file_path) is False:

        alart()

        log("Nothing!shutdown_flag")

    else:

        fg = file_mng.load(file_path)

        log(fg[0])

        file_mng.del_file(file_path)

 

def init():

    read()

    loop()

 

def fork():

        pid = os.fork()

                

        if pid > 0:

                file_mng.save('/var/run/shutdown_checkd.pid',str(pid))

                sys.exit()

        

        if pid == 0:

                init()

 

if __name__ == '__main__':

fork()

#init()

 

importしてある file_mng と gmail は以前に投稿したもの。

ファイル操作用のファイルマネージャーを作った - DreamerDreamのブログ

RaspberryPiからGmailを送る - DreamerDreamのブログ

 

フラグは起動時に消されるからどこでも良いんだけど

/usr/local/lib/shutdown.flag

にフラグを読み出し、

/usr/local/lib/shutdownlog.log

 にフラグの内容をシャットダウンの日時もしくは異常終了をログとして残すようにした。

メールアドレスはリスト形式で2つ登録して両方に送られるようになっている。

 

システム正常終了時に読み出されるのが

-- /usr/local/lib/shutdown_writed.py

#!/usr/bin/python

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

 

import datetime

 

file_path = "/usr/local/lib/shutdown.flag"

 

def save(filename,text):

    f = open(filename ,"w")

    f.write(text)

    f.close()

 

def get_daytime():

    now = datetime.datetime.now()

    return now.strftime("%Y/%m/%d %H:%M:%S")

  

if __name__ == '__main__':

    daytime = get_daytime()

    save(file_path,"shutdown:" + daytime)

日時を取得してフラグ用ファイルに出力しているだけ。

このコードにfile_mngをインポートしてないのはこっちの方が早いかなー?システム終了時には出来るだけ単純なコードの方が良いだろうという勝手な推測。