16
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

LINEでRaspberry PiにインストールしたAlexaを自由にしゃべらせる

Last updated at Posted at 2021-11-25

#本記事の内容

  • Raspberry PiにインストールしたAlexaを遠隔で自由にしゃべらせたいと思い、LINE経由でAlexaをしゃべらせることが出来るシステムを構築しました。

まず構成図は以下の通りです。
画像2.png

Alexaに指示を出すアプリとしてLINEを活用しました。システムは以下のように連携しています。

  • LINEで送ったメッセージが、LINEプラットフォームのLINE Messaging API経由で、Google Cloud Functionに連携される。

  • Google Cloud Functionは、受け取ったデータの中からテキストデータのみをGoogleのNoSQL DBであるCloud Firestoreに登録する。

  • Raspberry Piで稼働しているPythonアプリが、Cloud Firestoreのデータ更新を監視しており、データ更新時にそのデータをCloud Firestoreから取得する。

  • Pythonアプリが取得したメッセージでAlexaの音声再生スクリプトを実行し、AlexaをLINEで指定したメッセージでしゃべらせる。

LINE Messaging APIから連携されるWebhookを受け取る方法として、Cloud Functions for Firebaseで作成したアプリを利用することも可能ですが、FirabaseのCloud Functionの開発言語はJavaScriptだけで、Pythonが利用できないので、Google Cloud PlatformのCloudFunctionを利用することにしました。

本記事ではこれらのシステム構築に必要なことをまとめました。

#実施環境

  • ローカルPC環境

    • Windows 10
    • TeraTarm Version 4.9.4
  • ラズベリーパイ

    • Raspberry Pi 2 Model B

    • PLANEX 無線LAN子機 GW-USNANO2A ※Raspberry Pi 2はWi-Fi通信モジュールがないため、無線LAN子機をUSBに接続しWi-Fi通信を行う。

    • 家庭内の無線LANネットワーク環境にて実施

    • 音声認識マイク

    • マイクをUSBに接続する変換機

    • スピーカ

    • Python 3.9.7

    • Alexa Voice Service (AVS) Device SDK 1.24.0

    • Snowboy 1.3.0

  • クラウド環境

    • LINE Messaging API
    • Google Cloud Platform(以降、GCPと略す)
      • Cloud Function
    • Google Firebase
      • Cloud Firestore

alexa_01.jpg

#手順の流れ

  • 1.Cloud Firestoreの構築
    • 1.1.プロジェクトの作成
    • 1.2.Cloud Firestoreの設定
    • 1.3.認証キーの取得
  • 2.Cloud Functionの構築
    • 2.1.Cloud Functionの有効化
    • 2.2.関数の作成
  • 3.LINE Messaging APIの構築
    • 3.1.LINE Messaging API用のLINEアカウント作成とWebhook設定
  • 4.Raspberry Piの設定
    • 4.1.TeraTarmでsshログインする
    • 4.2.Firebase環境の構築
    • 4.3.Cloud Storeへのテスト接続
    • 4.3.Pythonアプリの配置
  • 5.動作確認
    • 5.1.Alexaの起動
    • 5.2.Pythonアプリの起動
    • 5.3.LINEでテスト

1.Cloud Firestoreの構築

1.1.プロジェクトの作成

Google Firebaseのコンソールにログインし、プロジェクトを作成をクリックする。
01.png

プロジェクト名を入力し、規約を確認し同意のチェックをクリックし、続行をクリックする。
02_.png

Google アナリティクスの設定画面が出るので必要に応じて有効化する。
私は使わないため有効にするのチェックを外し、プロジェクトを作成をクリック。
03.png

04.png

「新しいプロジェクトの準備ができました」のメッセージが出るので、続行をクリックする。
05_.png

1.2.Cloud Firestoreの設定

左のメニューからFirestore Databaseをクリックし、データベースの作成をクリックする。
50_.png

本番環境モードで開始するをクリックし、次へをクリックする。
51_.png

ロケーションに変更の必要がなければそのままの設定で、有効にするをクリックする。
52_.png

53_.png

コレクションを開始をクリックする。
54_.png

コレクションIDを入力し、次へをクリックする。※ここの値はPythonアプリで利用するのでメモしておく。
55_.png

ドキュメントIDのセルにある自動IDをクリックする。
56_.png

番号が払い出されるので、保存をクリックする。
57_.png

58_.png

1.3.認証キーの取得

プロジェクトの概要の隣の設定ボタン(歯車) > プロジェクトの設定をクリック
key_01.png
key_02.png

プロジェクトの設定上部のタブのサービスアカウントをクリックし、Admin SDK 構成スニペットをPythonに変更し、新しい秘密鍵の生成をクリックする。
key_03.png

キーを生成をクリックし、PCに保存する。
key_04.png

ここで取得した秘密鍵はラズパイからCloud Firestoreにアクセスする際に利用する。

2.Cloud Functionの構築

2.1.Cloud Functionの有効化

前提としてすでに、GCPにプロジェクトを作成済みであること。
もし未作成であれば、こちらの記事を参考に作成してください。
ラズパイ連携に向けたGoogleSheetsAPIにおけるサービスアカウントの作成

GCPのコンソールを開いて、左のメニューからCloud Functionをクリックします。
gcp_01.png

課金設定がまだの場合、課金を有効化するをクリックする。
gcp_02.png

請求先アカウントを選択し、アカウントを設定をクリックする。
gcp_03.png
gcp_04.png

これでCloud Functionを利用する準備が整った。
gcp_05.png

2.2.関数の作成

関数を作成をクリックする。
gcp_05.png

関数名、リージョン、トリガーのタイプ(HTTP)、認証(未認証の呼び出しを許可)を設定し、次に進む。
gcp_06.png
gcp_07.png

ここで表示されるURLは、LINEのWebhook設定で利用するのでメモしておくこと。

※本当であれば、認証ありでやりたいのですが、LINE Messagin APIのWebhookの仕組みにCloud Functionの認証を組み込めないので、未認証とします。

ランタイムの内容はデフォルトで問題なければそのまま進み、画面下部の次へをクリックする。
gcp_08.png

メッセージでCloud Build APIの有効化を促されたので、APIを有効にするをクリックして有効化する。
gcp_09.png
gcp_20.png
gcp_21.png

関数の編集画面に戻り、ランタイムをPython 3.9に変更し、エントリポイントをmain()に変更する。
main.pyの関数には、LINEのWebhook応答用に暫定的に以下のコードを入力する。

main.py
def main(request):
    return {"statusCode": 200}

左側のrequirements.txtには以下の値を記載しておく。

# Function dependencies, for example:
# package>=version
line-bot-sdk
firebase-admin

左側のボタンを押下し、1.3で取得した認証キーファイルと同じものを作成しておく。
ファイル名は、serviceAccountKey.jsonしておく。

{
  "type": "service_account",
  "project_id": "",
  "private_key_id": "",
  "private_key": "",
  "client_email": "",
  "client_id": "",
  "auth_uri": "",
  "token_uri": "",
  "auth_provider_x509_cert_url": "",
  "client_x509_cert_url": ""
}

変更後の画面はこのような形になるので、最後にデプロイをクリックする。
gcp_10.png

★★ 3.1の手順最後にあるLINEのWebhookの検証が完了したら、main.pyは以下の本番用のソースコードに差し替えること。 ★★

main.py
import base64
import hashlib
import hmac
import os

import firebase_admin
from firebase_admin import firestore
from firebase_admin import credentials

from flask import abort

from linebot import (
    LineBotApi, WebhookParser
)
from linebot.exceptions import (
    InvalidSignatureError
)
from linebot.models import (
    MessageEvent, TextMessage, TextSendMessage
)


def main(request):
    channel_secret = os.environ.get('LINE_ACOUNT_SECRET')
    channel_access_token = os.environ.get('LINE_ACCOUNT_ACCESS_TOKEN')

    line_bot_api = LineBotApi(channel_access_token)
    parser = WebhookParser(channel_secret)

    # Line Message APIのリクエスト検証
    body = request.get_data(as_text=True)
    hash = hmac.new(channel_secret.encode('utf-8'), body.encode('utf-8'), hashlib.sha256).digest()
    signature = base64.b64encode(hash).decode()
    if signature != request.headers['X_LINE_SIGNATURE']:
        return abort(405)

    try:
        events = parser.parse(body, signature)
    except InvalidSignatureError:
        return abort(405)

    # テキストメッセージがWebhookされたときだけ処理を行う。
    for event in events:
        if not isinstance(event, MessageEvent):
            continue
        if not isinstance(event.message, TextMessage):
            continue

        print(f'event message  : {event.message} , type : {type(event.message)}')
        print(f'event message text : {event.message.text}')

        # Firebase 初期化
        if not firebase_admin._apps:
            cred = credentials.Certificate("./serviceAccountKey.json")
            firebase_admin.initialize_app(cred)

        db = firestore.client()

        # テキストメッセージの登録
        doc_ref = db.collection(u'line-message')
        doc_ref.add({
            u'text': f'{event.message.text}'
        })

        # 応答メッセージを返却
        line_bot_api.reply_message(
            event.reply_token,
            TextSendMessage(text=event.message.text + " をお家ちゃんが読み上げます")
        )
    return {"statusCode": 200}

また、Google Cloud Founctionのランタイム環境変数に以下を設定する。
LINE_ACOUNT_SECRET:LINE Messageing APIのチャネルシークレット
LINE_ACCOUNT_ACCESS_TOKEN:LINE Messageing APIのチャネルアクセストークン

そうすることで、Line Message APIのリクエスト検証が実施される。

3.LINE Messaging APIの構築

3.1.LINE Messaging API用のLINEアカウント作成とWebhook設定

LINE Developersのウェブページにアクセスし、ログインをクリックする。
20.png

LINEアカウントでログインをクリックする。
21.png

好きな方法でLINEにログインする。
22.png

画面の右下にある言語設定を"English"から"日本語"に変更する。
"開発者名(Developer name)"と"メールアドレス(Your email)"を入力し、契約を確認し同意のチェックをクリックし、アカウントを作成をクリックする。
23.png

ポータル画面に遷移するので画面下部の新規プロバイダー作成をクリックする。
25.png
26.png

プロバイダー名を入力し、作成をクリックする。
27.png

チャネル設定からMessaging APIをクリックする。
28.png
29.png

"チャンネル名"、"チャンネル説明"、"大業種"、"小業種"の情報を入力し、規約の同意をチェックし、作成をクリックする。
30.png
31.png
32.png
33.png

OKをクリックする
34.png

同意するをクリックする。
35.png

チャンネルが作成されたので、"Messaging API設定"をクリックする。
36.png

下にスクロールするとWebhook URL設定があるので、編集をクリックする。Webhook URLに値を入力し更新をクリックする。
37.png
38.png

URLには先程Cloud Functionで設定したURLを設定する。

検証をクリックする。問題なければ、以下のように「成功」のメッセージが表示される。
39.png

Webhookの利用をチェックする。
41.png

3.2.LINE Messaging API用の自動応答メッセージの無効化

91.png
上記の画面で「応答メッセージ」の右側にある「編集」をクリックする。

92.png
詳細設定の「応答メッセージ設定」をクリックする。

93.png
「ステータス」が「オン」になっているので「オフ」に切り替える。

94.png
こちらを行うことで、Google Cloud Floumctionで生成したリプライメッセージが返却できる。

4.Raspberry Piの設定

4.1.TeraTarmでsshログインする

WindowsにてTeraTarmを起動して、ラズパイにSSH接続する。

4.2.Firebase環境の構築

・Firebase用のディレクトリ作成

cd /home/pi;pwd
mkdir firestoreapp
ls -ld firestoreapp

・Pythonの仮想環境作成

cd /home/pi/firestoreapp;pwd
python -m venv --system-site-packages ./venv
source ./venv/bin/activate
python -V
pip install --upgrade pip

・Firebaseのライブラリーを追加する

pip install --upgrade firebase-admin

上記のコマンドで、google-cloud-coreとgoogle-cloud-firestoreも入るはず。
ここでインストールされるgrpcio-1.41.1に後々苦しめられることになった。。対処法は次の内容。

・grpcioの再インストール

Pythonアプリを動かす中で以下のようなエラーが発生した。

★エラー1

from grpc._cython import cygrpc as _cygrpc
ImportError: /home/pi/firestoreapp/venv/lib/python3.9/site-packages/grpc/_cython/cygrpc.cpython-39-arm-linux-gnueabihf.so: undefined symbol: __atomic_exchange_8

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/pi/firestoreapp/./rs-listener-test.py", line 3, in <module>
    from firebase_admin import firestore
  File "/home/pi/firestoreapp/venv/lib/python3.9/site-packages/firebase_admin/firestore.py", line 28, in <module>
    raise ImportError('Failed to import the Cloud Firestore library for Python. Make sure '
ImportError: Failed to import the Cloud Firestore library for Python. Make sure to install the "google-cloud-firestore" module.

★エラー2

  File "/home/pi/firestoreapp/venv/lib/python3.9/site-packages/grpc/__init__.py", line 22, in <module>
    from grpc import _compression
  File "/home/pi/firestoreapp/venv/lib/python3.9/site-packages/grpc/_compression.py", line 15, in <module>
    from grpc._cython import cygrpc
ImportError: /lib/arm-linux-gnueabihf/libc.so.6: version `GLIBC_2.33' not found (required by /home/pi/firestoreapp/venv/lib/python3.9/site-packages/grpc/_cython/cygrpc.cpython-39-arm-linux-gnueabihf.so)

これらのエラーについていろいろ調査しトライ&エラーしたところ、これから記載する対応でクリアできた。
どうやらfirebase-adminのインストール途中にgrpcioのインストールがこけていたり、
grpcioが要求するglibcバージョンがインストールされているglibcのバージョンと異なっているためにエラーとなっているらしいと情報を掴んだため、
少し前の世代のgrpcioのインストールパッケージをPyPiから取得し、強制的に再インストールすることにした。

PyPIのgrpcioのページに行き、arm用の「grpcio-1.40.0-cp39-cp39-linux_armv7l.whl」をPCにダウンロードする。

ダウンロードしたパッケージをTera Tarmのscp機能を用いて、ラズパイに配置し、以下のコマンドで再インストールを行う。

pip install --force-reinstall grpcio-1.40.0-cp39-cp39-linux_armv7l.whl

※このコマンドは、ダウンロードしたパッケージを置いた場所で実施すること。

TeraTarmのファイル転送機能を利用し、1.3で取得した認証キーをラズパイのFirebaseディレクトリに格納する。

ls -l /home/pi/firestoreapp/serviceAccountKey.json

4.3.Cloud Storeへのテスト接続

接続確認用のアプリ(rs-listener-test.py)を配置し、実行権限を付与する。

ls -l /home/pi/firestoreapp/rs-listener-test.py
chmod 755 /home/pi/firestoreapp/rs-listener-test.py
ls -l /home/pi/firestoreapp/rs-listener-test.py

接続確認用のアプリのコードは以下のようなもの。

rs-listener-test.py
import firebase_admin
from firebase_admin import credentials
from firebase_admin import firestore


def main():
    print('auth start')
    cred = credentials.Certificate("./serviceAccountKey.json")
    firebase_admin.initialize_app(cred)
    print('auth finish')

    # Firestore アクセス
    db = firestore.client()
    doc_ref = db.collection(u'line-message') #Firesotre構築時に記載したコレクションIDを指定する。

    # テストデータの登録
    doc_ref.add({
        u'text': u'Test Access Succes'
    })

    # テストデータの読み込み
    docs = doc_ref.stream()
    for doc in docs:
        print(f'{doc.id} => {doc.to_dict()}')


if __name__ == '__main__':
    main()

仮想環境の有効化

cd /home/pi/firestoreapp;pwd
source ./venv/bin/activate

接続確認用アプリの実行

python ./rs-listener-test.py

接続が上手くいけば以下のようなデータがログとして出力されます。

(venv) pi@raspberrypi:~/firestoreapp $ python ./rs-listener-test.py
auth start
auth finish
6WNqnDJCuee2NK4Zrb7y => {'text': 'Test Access Succes'}
VOd4hHeB8NORqkHW5eNU => {}
(venv) pi@raspberrypi:~/firestoreapp $

Firestoreのコンソール上でも以下のようにテストデータが値が追加されたことが分かります。

(接続用アプリ実行前)
test_01.png

(接続用アプリ実行後)
test_02.png
Test Access Succesのデータが登録されています。

4.3.Pythonアプリの配置

本番用のアプリ(rs-listener.py)をTeratarmのSCP機能を用いて配置し、実行権限を付与する。

ls -l /home/pi/firestoreapp/rs-listener.py
chmod 755 /home/pi/firestoreapp/rs-listener.py
ls -l /home/pi/firestoreapp/rs-listener.py

アプリのコードは以下です。

rs-listener.py
import subprocess
import threading
import time
import firebase_admin
from firebase_admin import credentials
from firebase_admin import firestore


def auth():
    print('auth start')
    # Firebase 初期化
    if not firebase_admin._apps:
        cred = credentials.Certificate("/home/pi/firestoreapp/serviceAccountKey.json")
        firebase_admin.initialize_app(cred)
    print('auth finish')


def listen_document():
    # [START firestore_listen_document]
    print('client set')
    db = firestore.client()

    # Create an Event for notifying main thread.
    callback_done = threading.Event()
    print('set callback')

    # Create a callback on_snapshot function to capture changes
    def on_snapshot(doc_snapshot, changes, read_time):
        for doc in doc_snapshot:
            print(f'Received document snapshot: {doc.id} ,data : {doc.to_dict()} ,message : {doc.to_dict().get("text")}')

            cmd = ["/home/pi/tool/alexa-remote-control/alexa_remote_control.sh", "-e", f"""speak:<amazon:domain name='conversational'>{doc.to_dict().get("text")}</amazon:domain>"""]
            subprocess.call(cmd)

            db.collection(u'line-message').document(doc.id).delete()

        callback_done.set()

    doc_ref = db.collection(u'line-message')

    # Watch the document
    doc_watch = doc_ref.on_snapshot(on_snapshot)
    print('set Watch the document')
    # [END firestore_listen_document]


if __name__ == '__main__':
    auth()
    listen_document()
    while True:
        time.sleep(5)

5.動作確認

5.1.Alexaの起動

以下のコマンドで起動。

cd /home/pi/sdk-folder/sdk-build
PA_ALSA_PLUGHW=1 ./SampleApp/src/SampleApp ./Integration/AlexaClientSDKConfig.json ../third-party/snowboy/resources INFO

※Alexaのインストールについては、Raspberry piのスマートスピーカー化 (Amazon Alexaの公式インストールシェルが利用できないのでソースからインストールしてみた)の記事を参照ください。

5.2.Pythonアプリの起動

仮想環境の有効化

cd /home/pi/firestoreapp;pwd
source ./venv/bin/activate

Pythonアプリの実行

python ./rs-listener.py

以下のようなログが出力され、Cloud Firestoreの更新待ちとなる。

(venv) pi@raspberrypi:~/firestoreapp $ python ./rs-listener.py
auth start
auth finish
client set
set callback
set Watch the document

5.3.LINEでテスト

ここまでで動作確認の準備は終了。
以下の動画のように、LINEを使ってメッセージを入力してみました。

LINEに入力した「こんにちは、今日はいい天気ですね」が、無事 Alexaから再生され、やりたいことが実現できました。
いろいろと手こずりましたが、何とか達成できて嬉しいです。

また、LINEで入力したメッセージを無視されることがあることが分かりました。
応答メッセージがないので、LINE Messaging APIとCloud Function間の連携でこけていると予想します。
やりたいことが出来たのでいったん完了とし、調査はまた今度とします。

追記

追記1(2021/11/26).LINEで入力したメッセージが無視されることがある件の改善

また、LINEで入力したメッセージを無視されることがあることが分かりました。
応答メッセージがないので、LINE Messaging APIとCloud Function間の連携でこけていると予想します。
やりたいことが出来たのでいったん完了とし、調査はまた今度とします。

こちら調査したところ、Cloud Functionにおけるfirebase_adminの初期化処理において、初期化済みであるにも関わらずも一度初期化を行ったときに発生するエラーで処理がこけていました。

check if a Firebase App is already initialized in python

★エラー

in initialize_app raise ValueError(( ValueError: The default Firebase app already exists. This means you called init	ialize_app() more than once without providing an app name as the second argument. In most cases you only need to cal	l initialize_app() once. But if you do want to initialize multiple apps,
pass a second argument to initialize_app() to give each app a unique name.

関数の一回目と二回目の起動時間が短いと、一回目の関数で初期化したfirebase_adminが破棄されずに残っているようです。
プログラムの中で、firebase_admin._appsが残っているかどうか判定してから初期化するコードに改善しました。

main.py
# Firebase 初期化
if not firebase_admin._apps:
    cred = credentials.Certificate("./serviceAccountKey.json")
    firebase_admin.initialize_app(cred)

追記2(2021/11/26). Pythonのアプリの自動起動設定

Alexaを自動起動しているのに、わざわざPythonアプリを手動起動させるのは面倒なので、自動起動設定をしました。

以下のファイルの読み込みをフルパス指定に変更。

rs-listener.py
cred = cedentials.Certificate("/home/pi/firestoreapp/serviceAccountKey.json")

起動スクリプトの作成。

vi /home/pi/alexa-line-control.sh
chmod 755 /home/pi/alexa-line-control.sh

alexa-line-control.shシェルの中身は以下の通り。

#!/bin/bash

source /home/pi/firestoreapp/venv/bin/activate
python /home/pi/firestoreapp/rs-listener.py

自動起動用のファイルを作成する。

sudo vi /etc/systemd/system/lineControler.service

ファイルの中身は以下の通り。

[Unit]
Description = Line Controler for Alexa
[Service]
Restart = always
WorkingDirectory=/home/pi/
ExecStart = /home/pi/alexa-line-control.sh
ExecReload = /bin/kill -s HUP ${MAINPID}
ExecStop=/bin/kill -s TERM ${MAINPID}
user=pi
[Install]
WantedBy = multi-user.target

システムコマンドで起動できるか確認。

sudo systemctl start lineControler.service
sudo systemctl status lineControler.service

起動すると以下のようなメッセージが出る。

pi@raspberrypi:~ $ sudo systemctl status lineControler.service
● lineControler.service - Line Controler for Alexa
   Loaded: loaded (/etc/systemd/system/lineControler.service; enabled; vendor preset: enabled)
   Active: active (running) since Fri 2021-11-26 13:36:42 JST; 4s ago
 Main PID: 1241 (alexa-line-cont)
    Tasks: 2 (limit: 1935)
   CGroup: /system.slice/lineControler.service
           tq1241 /bin/bash /home/pi/alexa-line-control.sh
           mq1242 python /home/pi/firestoreapp/rs-listener.py

11月 26 13:36:42 raspberrypi systemd[1]: Started Line Controler for Alexa.
pi@raspberrypi:~ $

システムコマンドで停止できるか確認。

sudo systemctl stop lineControler.service
sudo systemctl status lineControler.service

停止が上手くいけば以下のようなメッセージが出る。

pi@raspberrypi:~ $ sudo systemctl status lineControler.service
● lineControler.service - Line Controler for Alexa
   Loaded: loaded (/etc/systemd/system/lineControler.service; enabled; vendor preset: enabled)
   Active: inactive (dead) since Fri 2021-11-26 13:38:00 JST; 4s ago
  Process: 1241 ExecStart=/home/pi/alexa-line-control.sh (code=killed, signal=TERM)
  Process: 1292 ExecStop=/bin/kill -s TERM ${MAINPID} (code=exited, status=0/SUCCESS)
 Main PID: 1241 (code=killed, signal=TERM)

11月 26 13:36:42 raspberrypi systemd[1]: Started Line Controler for Alexa.
11月 26 13:38:00 raspberrypi systemd[1]: Stopping Line Controler for Alexa...
11月 26 13:38:00 raspberrypi systemd[1]: lineControler.service: Main process exited, code=killed, status=15/TERM
11月 26 13:38:00 raspberrypi systemd[1]: lineControler.service: Succeeded.
11月 26 13:38:00 raspberrypi systemd[1]: Stopped Line Controler for Alexa.
pi@raspberrypi:~ $

最後に自動起動設定の有効化

sudo systemctl enable lineControler.service

これでラズパイ起動時に「rs-listener.py」が自動実行されるはず。

追記3(2022/08/24). CloudFunctionにおけるランタイム環境変数の設定

同じような事を再びやる機会があったため、本文を見直したところランタイム環境変数の設定手順が無いことに気づいた。
修正を実施しました。

Google Cloud Founctionにランタイム環境変数に以下を設定する。
LINE_ACOUNT_SECRET:LINE Messageing APIのチャネルシークレット
LINE_ACCOUNT_ACCESS_TOKEN:LINE Messageing APIのチャネルアクセストークン

そうすることで、Line Message APIのリクエスト検証が実施される。

参考文献

本記事の作成に当たり、以下の情報を参考にさせて頂きました。

16
13
1

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
16
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?