Q&A

pythonのプログラムをherokuを使わず、サーバ上で常時起動させたい

前提・実現したいこと

まずはこのページを見てくださりありがとうございます。 ページの説明が長く、申し訳ございません。 アドバイス、助言くださると大変助かります。

現在LINE Messaging APIを使用して、ユーザからのテキストに対して、センサ情報を返すプログラムをherokuにあげて常時起動させています。 ある場所の混雑度をセンサで観測し、そこの混雑度をラインに送るといったことです。 (サーバは用意しています。) 構図はこんな感じ ・サーバー ・・ラインプログラム(herokuで動作)→app.py ・・ラズベリーパイのセンサから受け取ったテキストデータ→test.txt ・・センサから受け取ったデータを割合として出した数値→test.py

そして本題ですが、やりたいことと致しましては、app.pyがherokuで動作しているため、サーバ内にある、test.py、test.txtの数値を参照できないという問題があり、herokuを使わずにサーバ上でプログラムを常に動作させたいということです。

app.pyはLINE Messaging APIのサンプルプログラムをいただき、少し編集したものです

サーバについて無知なもので数時間悩みましたが解決策がうまくいかず、質問させていただいております。

LINEのWebhook URL は現在herokuのものを登録しています。ここを変えなければいけないことはわかっているのですが、何に変えればいいのか、その後の流れがいまいち掴めず、困っています。

調べたところ自前のサーバを使う際にはPHPを記述しなければならないのでしょうか?

該当のソースコード

#app.pyのコード
from flask import Flask, request, abort

from linebot import (
    LineBotApi, WebhookHandler
)
from linebot.exceptions import (
    InvalidSignatureError
)
from linebot.models import (
    MessageEvent, TextMessage, TextSendMessage,ImageSendMessage,
)
import datetime
import test #test.pyをインポート



app = Flask(__name__)


line_bot_api = LineBotApi('')
handler = WebhookHandler('')


@app.route("/")
def test():
    return "ok"


@app.route("/callback", methods=['POST'])
def callback():
    # get X-Line-Signature header value
    signature = request.headers['X-Line-Signature']

    # get request body as text
    body = request.get_data(as_text=True)
    app.logger.info("Request body: " + body)

    # handle webhook body
    try:
        handler.handle(body, signature)
    except InvalidSignatureError:
        print("Invalid signature. Please check your channel access token/channel secret.")
        abort(400)

    return 'OK'


@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
    dt_now = datetime.datetime.now()
    jst_hour=dt_now.hour+9

    
    
    
                          
    if (0<=jst_hour<=9) or (16<=jst_hour):
        line_bot_api.reply_message(
                event.reply_token,
                TextSendMessage(text=f"混雑度提供時間は10時〜15時です。"))

    
    else:
        
        if event.message.text=="A":
            pec=test.main()
            line_bot_api.reply_message(
                event.reply_token,
                TextSendMessage(text=pec))#test.pyの値を参照できていないため、ここで既読無視状態になる

        elif event.message.text=="B":
            line_bot_api.reply_message(
                event.reply_token,
                TextSendMessage(text=f"現在のBの混雑度は??%です。"))

        elif event.message.text=="C":
            line_bot_api.reply_message(
                event.reply_token,
                TextSendMessage(text=f"現在のCの混雑度は??%です。"))       
        else:
            line_bot_api.reply_message(
                event.reply_token,
                TextSendMessage(text=f"入力が間違っています。もう一度入力してください"))
                


if __name__ == "__main__":
    app.run()

#test.pyのコード
import re
import ast
import statistics

def main():
    with open('/home/test_temp.txt', 'r') as f:
        new_temp = (ast.literal_eval(re.findall('\[[^\]]*]', f.read())[-1]))
        ave_temp = statistics.mean(new_temp)
        min_temp = min(new_temp)
        percentage = int((min_temp / ave_temp)*100)

        #print(new_temp)
        #print(ave_temp)
        #print(min_temp)
        #print(str(percentage) + '%')

   #この場合だと81の値が返り値となる
    return percentage

if __name__ == "__main__":
    main()


[15.75, 16.50, 18.00, 18.00, 19.00, 21.50, 23.75, 25.50, 
 16.00, 16.25, 17.25, 18.00, 19.50, 22.75, 23.25, 23.75, 
 15.00, 16.00, 16.50, 18.00, 19.50, 22.50, 22.50, 22.25, 
 15.00, 15.25, 15.50, 16.50, 18.50, 21.00, 20.00, 19.00, 
 15.00, 15.50, 15.25, 15.50, 15.75, 15.25, 16.00, 15.75, 
 15.75, 14.75, 15.50, 16.00, 15.50, 16.25, 15.50, 16.00, 
 14.50, 14.75, 15.25, 15.00, 15.50, 15.75, 15.75, 15.50, 
 14.25, 14.00, 15.00, 14.50, 14.75, 14.25, 14.25, 14.75, 
 ]
 
[16.25, 16.75, 17.75, 18.25, 19.25, 21.75, 23.75, 26.00, 
 15.50, 15.75, 17.00, 18.00, 19.25, 22.25, 23.25, 24.00, 
 15.50, 15.50, 16.50, 18.00, 19.25, 22.50, 22.50, 22.75, 
 15.00, 15.00, 16.00, 16.75, 18.50, 21.25, 20.25, 18.25, 
 15.50, 15.25, 16.00, 15.50, 16.00, 15.25, 15.50, 15.75, 
 14.75, 15.00, 15.50, 15.50, 15.75, 16.25, 15.50, 16.00, 
 15.25, 15.25, 15.25, 16.00, 15.75, 15.50, 15.25, 15.00, 
 14.75, 13.75, 14.50, 15.25, 15.00, 14.00, 14.25, 14.25, 
 ]

 [16.50, 16.75, 17.75, 18.50, 18.75, 21.50, 23.75, 25.75, 
 15.50, 16.00, 16.75, 18.25, 19.50, 22.75, 23.25, 23.50, 
 15.25, 15.25, 16.25, 17.75, 19.50, 22.25, 22.75, 22.00, 
 14.75, 14.75, 15.25, 16.25, 18.50, 21.25, 19.75, 18.00, 
 15.25, 15.25, 15.25, 15.50, 15.75, 15.00, 15.75, 16.00, 
 15.25, 15.00, 15.75, 15.50, 15.50, 16.50, 14.75, 15.50, 
 15.00, 15.50, 15.50, 15.25, 15.75, 15.25, 15.50, 15.25, 
 14.75, 13.75, 15.50, 15.00, 15.00, 14.00, 14.75, 13.75, 
 ]
 
[15.75, 16.00, 17.75, 18.00, 19.50, 21.50, 23.50, 25.50, 
  16.00, 15.75, 17.00, 17.75, 19.25, 22.50, 23.50, 23.25, 
  15.25, 15.50, 16.50, 17.25, 19.25, 22.50, 22.25, 22.00, 
  14.75, 15.25, 15.75, 16.75, 18.75, 20.50, 19.75, 18.25, 
  15.25, 15.25, 15.25, 15.50, 15.75, 15.25, 15.00, 15.50, 
  15.25, 14.75, 15.25, 15.25, 15.25, 16.00, 15.50, 15.50, 
  15.00, 14.50, 15.00, 15.00, 15.75, 15.25, 15.50, 15.25, 
  14.50, 14.00, 15.25, 14.25, 15.00, 13.75, 14.25, 14.25, 
  ]

 [16.75, 16.50, 17.50, 17.75, 19.00, 21.50, 23.75, 25.75, 
  16.00, 15.25, 16.50, 17.75, 19.75, 22.75, 23.25, 23.75, 
  15.25, 15.75, 16.50, 17.50, 19.25, 22.25, 22.50, 22.00, 
  15.00, 15.50, 15.50, 16.75, 18.50, 21.00, 20.00, 18.25, 
  15.00, 15.25, 15.25, 15.50, 15.50, 15.00, 15.75, 15.75, 
  15.25, 14.50, 15.75, 16.00, 15.50, 15.75, 15.50, 15.50, 
  15.25, 15.25, 15.00, 14.50, 15.75, 14.75, 15.50, 14.75, 
  14.00, 14.00, 15.00, 14.50, 15.00, 13.75, 13.75, 13.75, 
 ]


  • 0
  • 6
  • 865
  • twitter facebook

我這邊提供另外一種作法。

  1. 首先你已經完成類似 python3 app.py -> 獲得一個類似 http://localhost:3000 的後端服務
  2. 接下來可以使用 https://ngrok.com/ 來去執行 ngrok http 3000 -> 他能自動產生一個暫時性的https供您做webhook

希望能幫助其他想快速嘗試的人,不需要額外在學習 heroku~

  • 0

困ったらprintしてlogを見る / エラー文は検索していけば何とかなると思います。後はご自身で頑張ってください。

具体的な案を1つあげます。

  1. app.pyにセンサデータを受け取るエンドポイントを足す お使いのプログラムではflaskというライブラリを使っています。まずはflaskについて調べてみるといいと思います。 例えば、jsonをhttp通信で受け取ってheroku内で処理する例はこうです。
@app.route("/sensor", methods=["POST"])
def save_sensor():
    sensor_data = request.json
    ## ここで |sensor_data|の処理をする
    ## ファイルに書き足す or postgresqlに書き込む
    return "ok"
  1. ラズベリーパイのセンサから受け取った値を、herokuが動いているサーバーのurl/sensorに向けてPOSTする
    • ラズベリーパイ内から直接POSTするのがいいと思います。
    • 何らかの方法でラズベリーパイの中でセンサデータを保存しているはずなので、それを読み出すプログラムをラズベリーパイの中で実行し、herokuへ送信すればいいと思います。送信方法は python http post 方法 と検索すればたくさん出てきます。別にpythonでなくても大丈夫です。

3.保存したデータを読み出す 値が読み出せないのはいくつか原因が考えられます。まずはheroku logsをしてみましょう。何か失敗していればログにちゃんと出ますし、何も出てこなければプログラム上は動作しています。 値が出てこないことに対して考えられる原因は/home/test_temp.txtがherokuサーバーに存在しない、呼び出しているライブラリastやstatisticsがherokuサーバーにまだインストールされていない、/home/test_temp.txtを読み込めてはいるが値がうまく計算できていない、でしょうか。

以降質問があれば、他のサイトのほうが支援が得られるかと思います。

  • 0

ご丁寧に教えてくださりありがとうございます。 1の方向では時間がかかりそうななのと難易度が少し高めなんですね。 少しksyt様がいってらっしゃるようにherokuでチャレンジしてみます。 現在、app.pyとtest.py, test.txtのあるディレクトリでadd,commit,pushしているのですが、なぜapp.pyでtest.pyを参照できないのかわからないです。 "herokuで動いているアプリにデータを送るコードだけをtest.pyに書けば良い" とおっしゃっている、データを送るコードとはどのようなものでしょうか? 未熟でどのようなものか想定もつきません。アドバイスいただけないでしょうか。

  • 0

まず、独自のドメインを取得する必要があります。こちらは有料です。 ドメインというのは 例えば ksyt.com のようなものです。 google domainなどがいいと思います。

次に独自ドメインとご自身のサーバーのipアドレスを紐付けます。 こちらはDNSというものにドメインとサーバーのipアドレスの対を登録する必要があります。 google domainならDNSの設定も簡単にできます。

また、messaging apiのwebhookエンドポイントにはhttpsが必須となっており、ご自身のサーバーに証明証が必要です。(https://developers.line.biz/ja/docs/messaging-api/building-bot/#set-up-bot-on-line-developers-console) let's encryptなどを使えば良いですが、dockerに慣れている場合はhttps-portalやcertbotを使うと自動で取得してくれて楽な気がします。

大まかにやるべきことを書きましたので、参考にしてください。 ちなみにherokuで行ったほうが楽です...というのもherokuで動いているアプリにデータを送るコードだけをtest.pyに書けば良いからです。

  • 0

ksytさん、ご回答ありがとうございます。 1についてですが、すでに関連するプログラムはサーバー内に移動しているんですが、、 Webhook URLに登録するURLが現在わからない状態です。 2についてなのですが、極力もうherokuは使わないでおきたいと考えています。

1の方で詳しく教えていただけませんでしょうか。 よろしくお願いいたします。

  • 0
  1. ご自身のサーバーにapp.pyを含む全てのプログラムを移動させる もちろんtest.pyを呼べるようになるので、LINEbotとセンサ情報が最終的に繋がります。

  2. herokuサーバーにセンサ情報をご自身のサーバーから送るようにする 同じくLINEbotとセンサ情報が最終的に繋がります。ただしherokuサーバーの中に書き込んだファイルはpostgresqlのようなデータベースを使わない限りそのうち消えてしまうので、注意が必要です。

自前のサーバーで使う言語は関係ないですよ!pythonでも必ずできます。 応援しています!

  • 0
Are you sure? question.vm