ラズパイで定時にランダムにステッカーを取出してLINE Notifyへ送付する

2018年9月26日

久々のラズパイネタです。

以前、「ラズパイから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に送付する

スポンサーリンク
この記事を書いた人

60爺

60路を越え、RaspberryPi と出会い、その関係でブログ開設(2017/2~)となりました。始めてみると、コツコツやるのが性に合ってしまい、漢字の記事から家の補修・将棋・windows10関係・別名・言い方などジャンルを拡大して今に至ってます。まだまだ、元気なので新たな話題を見つけて皆様に提供できればと思っています。「プロフィールはこちら

TIPSLINE_Notify

Posted by 60爺