Hobby Science&Experiment

愛と工作の日々

趣味でやっている工作や勉強したことのメモ書きです。

ゴミ出しの前日にLINEでアラートを出す【Python3】

私の自治体ではペットボトルや瓶・カンなどの回収は2週に1回しかないので出し忘れると大変です。あの悔しい思いを繰り返すのが嫌なので通知プログラムを作ることにしました。つまり設定した日程(例えば第1、第3金曜日とか)の前日にアラートを送ることにします。これはもちろんゴミ出し以外のスケジュールにも転用可能です。

f:id:tara-chang:20200501111628p:plain
今回の成果
pythonのdatetimeとかを使えばスケジュールは作れそうです。通知はスマートフォンやスマートウォッチで確認できるLINEに送るのが良いでしょう。pythonを定期実行する方法としてはwindowsですとタスクスケジューラが使えますが、ラズパイユーザーの私はcrontabを(初めて)利用してみようと思います。

この記事でやること

・Line notifyの導入
PythonでLINE送信
Pythonでゴミ出しカレンダーを作成
・ゴミ出しライン通知プログラム
・Crontabによる定期実行

LINE Notifyの設定

LINE Notifyに接続し、マイページ➡アクセストークンの発行と進みます。
notify-bot.line.me
この時トークン名を「ゴミ出し」とし、通知を送信するグループ(あらかじめ作成しておくと良い)を選択します。

Pythonでライン送信

次のプログラムを実行すればLINEが送信できます。tokenには先ほど発行したトークンを入力してください。こちらのコードを参考にしました。

import requests

def send_line(text):
    url ='https://notify-api.line.me/api/notify'
    token = "トークンを張り付け"
    headers ={'Authorization' : 'Bearer ' + token}
    message = text
    payload = {'message' : message}
    p = requests.post(url, headers=headers, data=payload)
    print(p)

text="てすてすてす"
send_line(text)

無事ラインが届きました。

Pythonでゴミ出しカレンダーを作成

まず明日の日付が何回目の何曜日なのかを判断します。こちらの記事の関数に1日分のタイムデルタを加算しただけです。結果には(第n週、X曜日)というタプルが返されます。

import calendar
import datetime

def get_nth_week(day):
    return (day - 1) // 7 + 1

def get_nth_dow(year, month, day):
    return get_nth_week(day), calendar.weekday(year, month, day)

today = datetime.datetime.now() #現在日時取得
tomorrow = today + datetime.timedelta(days=1) #現在日時に+1日のタイムデルタを加算
tom_nth_dow = get_nth_dow(tomorrow.year, tomorrow.month, tomorrow.day) #明日の(第n週、X曜日)を取得

print("today:", today)
print("tomorrow:", tomorrow)
print("tom_nth_dow:", tom_nth_dow)

結果

today: 2020-04-30 21:21:00.556439
tomorrow: 2020-05-01 21:21:00.556439
tom_nth_dow: (1, 4)

となります。ここで出力された(1,4)は第1回目の金曜日であることを表します。
次にゴミ出しのカレンダーを作成します。pandasのDataFrameを利用しました。列方向は曜日で行方向はその月で何回目かを表しています。

import pandas as pd

schedule=pd.DataFrame([
["Mon" ,"Tue"         ,"Wed"   ,"Thurs" ,"Fri"      ,"Sat", "Sun"],
[""    ,"プラスチック" ,""      ,""      ,"ビン・カン",""   ,""    ],
[""    ,""            ,"金物"   ,""      ,""        ,""   ,""    ],
[""    ,"プラスチック" ,""      ,""      ,"ビン・カン",""   ,""    ],
[""    ,""            ,"金物"   ,""      ,""        ,""   ,""    ],
[""    ,""            ,""      ,""      ,""        ,""    ,""   ],
])
print(schedule)

結果
f:id:tara-chang:20200501102126p:plain
最後に上の二つを組み合わせます。pandas DataFrameの.iatを使ってデータフレームの中の該当インデックスの値を取り出します。

date_jp = ['月','火','水','木','金',"土",'日']
date_check = schedule.iat[tom_nth_dow]
print("明日は第"+str(tom_nth_dow[0])+date_jp[tom_nth_dow[1]]+"曜日")
print(date_check+"回収の日です")

結果

明日は第1金曜日
ビン・カン回収の日です

tom_nth_dowには(1,4)、すなわち第1金曜日が入っていましたので、sheduleより"ビン・カン"が取り出されました。

ゴミ出しLINE通知プログラム

python3でLine送信とゴミ出しカレンダーを作ることが出来ましたので、あとは単純にこれを組み合わせて通知プログラムを作成します。

import calendar
import datetime
import pandas as pd
import requests

def get_nth_week(day):
    return (day - 1) // 7 + 1

def get_nth_dow(year, month, day):
    return get_nth_week(day), calendar.weekday(year, month, day)

def send_line(text):
    url ='https://notify-api.line.me/api/notify'
    token = "Line notifyトークンを張り付け"
    headers ={'Authorization' : 'Bearer ' + token}
    message = text
    payload = {'message' : message}
    p = requests.post(url, headers=headers, data=payload)
    print(p)

schedule=pd.DataFrame([
["Mon" ,"Tue"         ,"Wed"   ,"Thurs" ,"Fri"      ,"Sat", "Sun"],
[""    ,"プラスチック" ,""      ,""      ,"ビン・カン",""   ,""    ],
[""    ,""            ,"金物"   ,""      ,""        ,""   ,""    ],
[""    ,"プラスチック" ,""      ,""      ,"ビン・カン",""   ,""    ],
[""    ,""            ,"金物"   ,""      ,""        ,""   ,""    ],
[""    ,""            ,""      ,""      ,""        ,""    ,""   ],
])

date_jp = ['月','火','水','木','金',"土",'日']

today = datetime.datetime.now()
tomorrow = today + datetime.timedelta(days=1)
tom_nth_dow = get_nth_dow(tomorrow.year, tomorrow.month, tomorrow.day)
date_check = schedule.iat[tom_nth_dow]

text1 = "第"+str(tom_nth_dow[0])+date_jp[tom_nth_dow[1]]+"曜日"
text2 = "明日は"+date_check+"収集の日("+text1+")です。" 

if date_check =="":
    print("明日のゴミ出しは有りません")
else: 
    send_line(text2)

結果

明日はビン・カン収集の日(第1金曜日)です。

結果として翌日である5/1金曜がビン・カン回収の日であることがラインで送信されました。該当の回収がない場合は何も起こりません。これでプログラムは完成しましたので、後は定期実行の設定となります。windowsのタスクスケジューラなどでも可能ですが、本記事ではRaspberry Piでcrontabを利用したいと思います。

crontabを使った連続実行

LXTeminalでcrontabを編集できます。

crontab -e

末尾に次のように書き加えます。

00 20 * * * sudo python3 /home/pi/<プログラム名>.py

これは毎日20時00分に指定のコマンドを実行することを示しています。
ctrl+Xでcrontabを閉じれば作業は終了です。コードに何らかの不備があるとcrontabは何もアクションしませんので、次の設定で毎分実行などにしてみて動作確認ができてから、所望の時間に設定すると良いと思います。

*/1 * * * * sudo python3 /home/pi/<プログラム名>.py

狙い通りのラインが20時に送られてきました!
f:id:tara-chang:20200501111628p:plain