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

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

以前、ラズパイからcurlコマンドでLINE Notifyにメッセージとステッカーを送るを送れるという記事を載せました。

調べてみると、その記事は、2017年7月22日にアップしたんですが、内容が陳腐だったので、少し手を入れて見やすくしました。

それを行った際に、これを使って何かをしてみようと思い立ちました。

1.定時に LINE へメッセージ送付

60爺は、未だに毎日お仕事をさせていただいております。時間は、9時開始、17時20分終了です。

そこで、定時(仕事の終了10分前)に、この機能を使用してメッセージとステッカーを送付することにしました。

これだけでは、単純に curl コマンドを書けば終わってしまうのであまり面白くありません。

色々考えていたら、LINE Engineering BLOG の記事のここに目が行きました。

※送信できるStickerは、documentにも記載してありますがMessaging APIと同じものになっています。

そこで、このページを見ていくと、Sticker一覧を見つけました。かなりの数のステッカーがあり、これを利用できることがわかりました。

そこで、メッセージを送る前に乱数を発生させて、その日送付するステッカーを決定することにしました。

これならば、単純に curl 文を書くだけでないので、ちょっとした暇つぶしになると思います。

2.python プログラム作成

さて、python プログラムを作成します。

しかし、このところ、python プログラムに全く触れていなかったため、一から作成するのに非常に苦労しました。

プログラムは、次の手順を踏みます。

乱数発生 ⇒ ステッカーID決定 ⇒ curl コマンド生成  ⇒ curl コマンド発行

(1) 乱数発生

そうそう、乱数発生の前に、日付から曜日が土日か判断して、その場合はプログラムを終了させます。

土日はお休みですので、メッセージ送付は不要ですので。年末年始や祝祭日も除きたいのですが、まあ、緩く進めるので今回は無視したいと思います^^;

先ほどの Sticker一覧をみて、STKID を洗い出しました。この STKID ですが、1から始まり、632 で終わります。このため、乱数は 632 まで発生させます。

(2) ステッカーID決定

さて、上記で言った通り、Sticker は STKID でどの img なのか判断しています。そして、この STKID なんですが、全部で 632 個あるわけではありません。

そうです、欠番が結構あるんです。

そのため、乱数がその欠番を取り出した場合は、再度乱数を発生させて、有効なステッカー番号を取るまで繰り返すようにしました。

調べたところ、ステッカーには次の範囲の番号が存在します。有効な個数は344個です。

 1 ~ 47、100 ~ 307、401 ~ 430、501 ~ 527、601 ~ 632

(3) curl コマンド生成

STKID が決まったら、この番号を curl コマンドに指定できるようにします。

(4) curl コマンド発行

最後に、curl コマンドを発行します。subprocess.call で実施する予定です。

3.コマンド発行テスト

何で 60爺がプログラムを作ると問題が起こるのでしょうか?

まア、余り素直に動いても面白くないんですが、半日で終わりかなと思っていたのに2日も時間を取られてしまいました。

記録を残しますので、ご覧ください。

(1) ステッカー取得にはパッケージ識別子も必要

以下のコマンドに対して、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

(2) 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コマンドだけを切り取って流すと正常に流れます!!

curl -X POST https://notify-api.line.me/api/notify -H 'Authorization: Bearer vWjkChWETa5qPezWZr09KzWa520rlaxpCfyQKqEMUF4' -F 'message=あと10 分で、終了時間です !' -F 'stickerPackageId=1' -F 'stickerId=125'

上記、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

(3) シェルで対応しようとしたが、・・・・

訳の分からんエラーで先に進めないので、シェルで出来ないか可能性を探りました。下記のように変更してみました。

#!#!/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 は数値にしろなんて言われました。

調べると、シェルの引数は文字列なんですね。文字列を数字にできないか格闘しましたが、これも諦めました。

4.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に送付する