0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

WebhookでLINEからのメッセージに応答する

Posted at

はじめに

こちらはRaspberry Pi と LINE messaging API で作る監視カメラシリーズ第12弾です。

LINEからラズパイを制御するために必要なLINEのWebhook機能を作ります。

今回のコードでは、LINEで「おはよう」と送ると「おはようございます」と返信、
「こんにちは」と送ると「こんにちは!」と返信する機能を作成します。

LINE Webhookとは

ざっくり解説ですが、

Webhook(ウェブフック) とは、「あるシステムで特定のイベント(出来事)が発生した際に、別のシステムへ自動的に通知(データ)を送信する仕組み」です。

そして、LINE Webhook とは、ユーザーのアクション(友だち追加、メッセージ送信など)が発生した際に、そのイベント情報をLINEプラットフォームから指定した外部システム(ボットサーバーなど)へ自動的に通知(POSTリクエスト)する仕組みのことです。

メッセージ返信の流れ

ここではcpp-httplibで次の機能を作成し、メッセージ返信を実現します。

  1. POSTリクエストでLINE APIにメッセージを送信する機能(第9弾と同じような機能です)
     
  2. そして、Webhook URLにアクセスされたらメッセージを確認し、1.のメッセージ送信を呼び出して返信をするWebサーバーとしての機能です。(第10弾を使ってローカルから外部に公開します)

つまり、LINEに「おはよう」と送ると
LINE APIから「おはようというイベントだよー」とURLにアクセスが来ます、そしたら「なんのイベントかなー」と中身を確認します、そして「おはようだったらおはようございますって送ろー」と送信する感じです。
 →これでLINEでは「おはようございます」と返信されたようになります。

今回はシリーズ第8弾で取得するチャネルアクセストークンと、第10弾でのURLを使用します。

準備

LINE Webhookを使用する場合は、次の設定が必要です。

LINE Developers の設定

ログインしたらチャネルが表示されていると思いますので、使用しているチャネルを選択し、項目の「Messaging API設定」を選択します。

トップ > (プロバイダー名) > (チャネル名) > Messaging API設定
この状態です。

下にあるWebhooks設定を変更します。
スクリーンショット 2025-12-19 11.49.24.png

・Webhook URLを第10弾でのURLを使い、写真のようなURL/webhookにして更新します。(https://xxxx.xxxx.xxの部分を自分のURLに変更してください。)
※NgrokのURLが更新された場合は、都度変更が必要です。

・Webhookの利用を有効にします。

LINE Official Account Managerの設定

ログインしたら、チャネルを選択します。

右上の設定を選択し、応答設定を選択します。
スクリーンショット 2025-12-19 11.58.06.png

・Webhookを有効にします。
・応答メッセージは無効にします。
 ※LINEの標準システムが勝手に「メッセージありがとうございます!」と返信してしまい、プログラム側の返信が無視されることがあります。

以上で設定は完了です。

LINEに応答するコードです。

line_botディレクトリに移動し

cd /home/pi/projects/line_bot

main.cppを作成します

vim main.cpp

テキストエディタに次のコードを貼り付けます。

ここを変更するの部分はご自分のチャネルアクセストークンに置き換えてください。

main.cpp

#define CPPHTTPLIB_OPENSSL_SUPPORT // APIへの返信時にHTTPSクライアントとして動作するために必要

#include "httplib.h"
#include <iostream>
#include <string>
#include "nlohmann/json.hpp" // nlohmann/jsonを使用

using namespace httplib;
using json = nlohmann::json;

const std::string CHANNEL_ACCESS_TOKEN = "ここを変更する"; // チャンネルアクセストークン 
const int WEBHOOK_PORT = 8080;

// (1) LINE Messaging APIのReply Messageを送信する関数 (クライアント機能)
void send_reply_message(const std::string& reply_token, const std::string& text) {
    
    // HTTPSクライアントとしてLINE APIのホストに接続
    Client cli("https://api.line.me"); 
    
    // 返信用JSONデータの作成
    json reply_json = {
        {"replyToken", reply_token},
        {"messages", {
            {
                {"type", "text"},
                {"text", text}
            }
        }}
    };
    std::string post_data = reply_json.dump();

    // 必須ヘッダー: 認証トークンとContent-Type
    Headers headers = {
        {"Authorization", "Bearer " + CHANNEL_ACCESS_TOKEN}
    };
    
    // Reply APIを呼び出して返信を送信
    auto res = cli.Post("/v2/bot/message/reply", headers, post_data, "application/json");

    if (res && res->status == 200) {
        std::cout << "  > LINEへ返信しました: " << text << std::endl;
    } else {
        std::cerr << "  > 返信に失敗。HTTP ステータス: " << (res ? std::to_string(res->status) : "接続エラー") << std::endl;
        if (res) std::cerr << "  > レスポンス内容: " << res->body << std::endl;
    }
}

// (2) Webhookリクエストを処理するハンドラ関数 (サーバー機能)
void handle_webhook(const Request& req, Response& res) {
    // ----------------------------------------------------
    // 1. リクエストボディの解析
    // ----------------------------------------------------
    json req_json;
    try {
        req_json = json::parse(req.body);
    } catch (json::parse_error& e) {
        std::cerr << "JSON解析エラー: " << e.what() << std::endl;
        res.set_content("Bad Request", "text/plain");
        res.status = 400; 
        return;
    }

    std::cout << "Webhookリクエストを受信しました。処理を開始します。" << std::endl;

    // ----------------------------------------------------
    // 2. メッセージイベントの抽出と処理
    // ----------------------------------------------------
    // リクエストに含まれるすべてのイベントをループ
    for (const auto& event : req_json["events"]) {
        // イベントタイプが「メッセージ」かつ、メッセージタイプが「テキスト」であるか確認
        if (event.contains("type") && event["type"] == "message" && 
            event.contains("message") && event["message"].contains("type") && event["message"]["type"] == "text") {
            
            std::string user_message = event["message"]["text"];
            std::string reply_token  = event["replyToken"];

            std::cout << "  > ユーザーメッセージ: [" << user_message << "]" << std::endl;

            // ------------------------------------------------
            // 3. 応答ロジックの実装
            // ------------------------------------------------
            if (user_message == "おはよう") {
                send_reply_message(reply_token, "おはようございます");
            } else if (user_message == "こんにちは") {
                send_reply_message(reply_token, "こんにちは!");
            } else {
                // その他のメッセージには何も返信しない、またはデフォルトの応答
                std::cout << "  > 定義されていないメッセージのため、返信しません。" << std::endl;
            }
        }
    }

    // LINEプラットフォームに対して、リクエストを正常に受け取ったことを必ず伝える (ステータス200)
    res.set_content("OK", "text/plain");
    res.status = 200;
}

// (3) メイン関数
int main() {
    Server svr;

    // Webhookの受付パスとハンドラを設定
    svr.Post("/webhook", [](const Request& req, Response& res) {
        handle_webhook(req, res);
    });

    std::cout << "===================================================" << std::endl;
    std::cout << "LINE Webhook サーバーをポート " << WEBHOOK_PORT << " で起動します。" << std::endl;
    std::cout << "ngrok で外部に公開し、LINE DevelopersにURLを設定してください。" << std::endl;
    std::cout << "===================================================" << std::endl;
    
    // サーバーを起動し、リクエストを待ち受け
    if (!svr.listen("0.0.0.0", WEBHOOK_PORT)) {
        std::cerr << "サーバーの起動に失敗しました。ポートが使用中かもしれません。" << std::endl;
        return 1;
    }

    return 0;
}

ESCキーを押して、:wqを入力してEnterで保存して閉じます。

buildディレクトリに移動し、

cd build

makeコマンドでビルドします。

make

ここで、実行の前に、別のターミナルを開き、ラズパイにssh接続してからngrokを起動してください。

ngrok http 8080

元のターミナルに戻り、実行ファイルのmain_app./で実行します。

./main_app

LINEで「おはよう」や「こんにちは」と送って、返答を確認しましょう。

こちらはサーバーが待ち続けるため、処理の中断はctrキー + cを押してください。
サーバーの停止は全ての機能を合わせる時に実装します。

さいごに

webhook機能を使えばLINEの特定の文字列に反応してラズパイの制御を行えるので、単純なモード変更などの遠隔操作する手段として使用できます。
次に作りたいロボットカーでも何かに使えないか考えていると楽しいです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?