ラズパイで定時にランダムにステッカーを取出してLINE Notifyへ送付する
久々のラズパイネタです。
以前、「ラズパイからcurlコマンドでLINE Notifyにメッセージとステッカーを送る」という記事を載せました。
調べてみると、その記事は 2017年7月22日にアップしたんですが、内容が陳腐だったので少し手を入れて見やすくしました。
それを行った際に、これを使って何かをしてみようと思い立ちました。
定時に LINE へメッセージ送付
60爺は、未だに毎日お仕事をしております。
時間は、9時開始、17時20分終了です。そこで、定時(仕事の終了10分前)に、この機能を使用してメッセージとステッカーを送付することにしました。
これだけでは、単純に curl コマンドを書けば終わってしまうのであまり面白くありません。色々考えていたら、LINE Engineering BLOG の記事のここに目が行きました。
※送信できるStickerは、documentにも記載してありますがMessaging APIと同じものになっています。
そこで、このページを見ていくと、Sticker一覧を見つけました。かなりの数のステッカーがあり、これを利用できることがわかりました。
そこで、メッセージを送る前に乱数を発生させて、その日送付するステッカーを決定することにしました。これならば、単純に curl 文を書くだけでないので、ちょっとした暇つぶしになると思います。
python プログラム作成
さて、python プログラムを作成します。このところ python プログラムに全く触れていなかったこともあり、一から作成するのに非常に苦労しました。
プログラムの仕様は次の通りです。
乱数発生 ⇒ ステッカーID決定 ⇒ curl コマンド生成 ⇒ curl コマンド発行
乱数発生
乱数発生の前に、日付から曜日が土日か判断して、その場合はプログラムを終了させます。
土日は会社がお休みですのでメッセージ送付は不要です。年末年始や祝祭日も除きたいのですが、まあ、緩く進めるので今回は無視したいと思います^^;
先ほどの Sticker一覧をみて、STKID を洗い出しました。この STKID ですが、1から始まり、632 で終わります。このため、乱数は 632 まで発生させます。
ステッカーID決定
さて、上記で言った通り、Sticker は STKID でどの img なのか判断しています。そして、この STKID なんですが、全部で 632 個あるわけではありません。
そうです、欠番が結構あるんです。
そのため、乱数がその欠番を取り出した場合は、再度乱数を発生させて、有効なステッカー番号を取るまで繰り返すようにしました。
調べたところ、ステッカーには次の範囲の番号が存在します。有効な個数は344個です。
1 ~ 47、100 ~ 307、401 ~ 430、501 ~ 527、601 ~ 632
curl コマンド生成
STKID が決まったら、この番号を curl コマンドに指定できるようにします。
curl コマンド発行
最後に、curl コマンドを発行します。subprocess.call で実施する予定です。
コマンド発行テスト
何で 60爺がプログラムを作ると問題が起こるのでしょうか?まア、余り素直に動いても面白くないんですが、半日で終わりかなと思っていたのに2日も時間を取られてしまいました。
記録を残しますので、ご覧ください。
ステッカー取得にはパッケージ識別子も必要
以下のコマンドに対して、Invalid stickerId なるエラーが発生しました。
curl -X POST https://notify-api.ization: Bearer アクセストークン" -F "message=あと10 分で、終了時間です!" -F "stickerPackageId=1" -F "stickerId=29"
{"status":400,"message":"Invalid stickerId."}
最初、何を言っているのかわからなかったのですが、先程の Sticker一覧をよく見ると、Sticker識別子(stickerId)の他にパッケージ識別子(stickerPackageId)なるものが存在しており、これが誤っていました。
60爺は、パッケージ識別子は1しかないと勘違いしていたんです。今回、パッケージ識別子を2にすると正しく動作しました。
うーーん!まさか、パッケージ識別子に1以外が入ってくるとは思いませんでした。Sticker一覧を見直したところ、パッケージ識別子には1~4が入ることがわかりました。
さらに調べてみたところ、パッケージ識別子とSticker識別子の関係は以下の通りになっています。
- パッケージ識別子1 1 ~ 17、21、100 ~ 139、401 ~ 430
- パッケージ識別子2 18 ~ 20、22 ~ 47、140 ~ 179、501 ~ 527
- パッケージ識別子3 189 ~ 259
- パッケージ識別子4 260 ~ 307、601 ~ 632
subprocess.callでエラー発生
さて、上記の2つの識別子の取り込みを終わり、curlコマンドの組み立ても完了し、コマンド発行をしたところ、うまくいかずエラーが発生です。
{"status":401,"message":"Missing authorization header"}
curl: (6) Could not resolve host: Bearer
curl: (6) Could not resolve host: アクセストークン"
curl: (6) Could not resolve host: xn--!"-nxxxxxxxxxxxxxx
実際、作成したcurl文はこれです。
curl -X POST https://notify-api.line.me/api/notify -H 'Authorization: Bearer vWjkChWETa5qPezWZr09KzWa520rlaxpCfyQKqEMUF4' -F 'message=あと10 分で、終了時間です !' -F 'stickerPackageId=1' -F 'stickerId=125'
どういう訳か、このcurlコマンドだけを切り取って流すと正常に流れます!!
上記、401のエラーを検索したところ、以下の解決法が出ています。
これですが、シングルクォーテーションではなくダブルクォーテーションで囲むと解決したので、試してみてください。
しかし、以下のように、シングルクォーテーションではなくダブルクォーテーションに変更しても、エラーは全く同じでした。
curl -X POST https://notify-api.line.me/api/notify -H "Authorization: Bearer アクセストークン" -F "message=あと10 分で、終了時間です !" -F "stickerPackageId=1" -F "stickerId=10"
{"status":401,"message":"Missing authorization header"}
curl: (6) Could not resolve host: Bearer
curl: (6) Could not resolve host: アクセストークン"
curl: (6) Could not resolve host: xn--!"-nxxxxxxxxxxxxxx
シェルで対応しようとしたが、・・・・
訳の分からんエラーで先に進めないので、シェルで出来ないか可能性を探りました。下記のように変更してみました。
#!#!/bin/sh
PaPckageId=`expr $1`
stickerId=`expr $2`
curl -X POST https://notify-api.line.me/api/notify -H 'Authorization: Bearer アクセストークン' -F 'message=test' -F 'stickerPackageId=${PackageId}' -F 'stickerId=${stickerId}'
しかし、実行すると次のエラーが発生します。
{"status":400,"message":"StickerPackageId must be number value."}
StickerPackageId は数値にしろなんて言われました。
調べると、シェルの引数は文字列なんですね。文字列を数字にできないか格闘しましたが、これも諦めました。
os関数を使用したら解決
結局、pythonのプログラムに戻り、subprocess.callの代わりに、os.systemを使用したら、あっさりと解決し、コマンド発行も無事終わりました。
先程までの格闘は何だったのでしょうか?
まあ、ともあれ、プログラムは完成しました。
あとは、祭日も土日と同じようにするとか考えられますが、ひとまず、crontab で17時10分にプログラムを起動するようにしました。
最後に、稚拙ですがプログラムを公開します。
import random
import os
import datetime
import sys
#import subprocessdef rdm_return():#ステッカーNo.取得
rdm = random.randrange(632) #乱数発生
if rdm >= 1 and rdm <= 47 : pass
elif rdm >= 100 and rdm <= 307 : pass
elif rdm >= 401 and rdm <= 430 : pass
elif rdm >= 501 and rdm <= 527 : pass
elif rdm >= 601 and rdm <= 632 :
pass
else:
rdm = 0 return(rdm)def STKPKGID_return(STKID):
#ステッカーID取得
STKPKGID = 1
if STKID >= 1 and STKID <= 17 : pass
elif STKID == 21 : pass
elif STKID >= 100 and STKID <= 139 : pass
elif STKID >= 401 and STKID <= 430 :
pass
elif STKID >= 189 and STKID <= 259 :
STKPKGID = 3
elif STKID >= 260 and STKID <= 307 :
STKPKGID = 4
elif STKID >= 601 and STKID <= 632 :
STKPKGID = 4
else
STKPKGID = 2
return(STKPKGID)
#プログラム開始
today = datetime.date.today() # 現在の日付を取得
if today.weekday() == 5 or today.weekday() == 6 :
sys.exit()
sticker_no = 0
while sticker_no == 0 :
sticker_no = rdm_return()
print(sticker_no)sticker_id = STKPKGID_return(sticker_no)
# コマンド作成
#cmd1 = "curl -X POST https://notify-api.line.me/api/notify -H 'Authorization: Bearer アクセストークン' -F 'message=あと10 分で、終了時間です!' -F 'stickerPackageId="
cmd1 = 'curl -X POST https://notify-api.line.me/api/notify -H "Authorization: Bearer アクセストークン" -F "message=あと10 分で、終了 時間です!" -F "stickerPackageId='
cmd2 = '" -F "stickerId='
cmd3 = '"'
cmd = cmd1 + str(sticker_id) + cmd2 + str(sticker_no) + cmd3
# コマンド発行
#subprocess.call(cmd.split())
os.system(cmd)
print(cmd)
2020年8月末で現役を退きました。このため、ステッカー送付は終了して、今では定時に天気予報を送付するようにしています。
Pythonで天気情報を取得しLINE Notifyに送付する
ディスカッション
コメント一覧
まだ、コメントがありません