Node.jsでLINEボット用のユーティリティクラスを作成したので、立ち上げるまでをまとめておきます。(時間がたつと忘れてしまうので)
ついでに、ESP32でLINEビーコンを作成し、LINEボットで連携します。
(とは言っても、今まで複数投稿してきた内容をまとめただけです。ベースとなった投稿は、本投稿の最後に示しておきました。)
以下のAWS Lambdaエミュレーション環境をベースにします。
poruruba/amplify_template
https://github.com/poruruba/amplify_template
先に順番を示しておきます。
・LINEチャネルの作成
・Node.jsサーバ立ち上げ
・Node.jsサーバにエンドポイントの作成
・LINEボットWebhook設定
・友達登録
・メッセージ応答のカスタマイズ
・(必要に応じて)ESP32でLINEビーコンを作成
LINEチャネルの作成
LINEデベロッパーコンソールから登録します。
LINEデベロッパーコンソール
https://developers.line.biz/console/
プロバイダを選択または新規作成したのち、チャネル設定の新規チャネルを選択します。
チャネルの種類は、Messaging APIです。
適当に入力し、利用規約に同意して、「作成」ボタンを押下します。
作成後に表示されるチャネル基本設定にあるチャネルシークレットとMessaging API設定にあるチャネルアクセストークン(長期)の発行ボタンで生成されるチャネルアクセストークン(長期)を覚えておきます。
また、Messaging API設定の応答メッセージは無効に変更しておきます。グループ・複数人チャットへの参加を許可するも有効にしておきます。
Node.jsサーバ立ち上げ
前提
Node.jsがインストールされていること
以下から、ZIPダウンロードします。
poruruba/express_template
https://github.com/poruruba/express_template
以下の通りに展開し、セットアップします。
> unzip express_template-master.zip
> cd express_template-master
> mkdir cert
> touch .env
> npm install
> node app.js
HTTPSである必要があるため、上記の途中でcertにSSL証明書を格納します。ファイル名は、app.jpを参照してください。
特に何もしなければ、HTTPSがポート10443で立ち上がるかと思います。
Node.jsサーバにエンドポイントの作成
LINEボット用のフォルダを作成します。
> mkdir api\controllers\linebot
上記フォルダに以下の2つのファイルを作成します。
・index.js
・swagger.yaml
LINEボットとして応答できるようにするためには、最低限以下の記載があればよいです。
'use strict';
const config = {
channelAccessToken: process.env.LINE_CHANNEL_ACCESS_TOKEN || '【LINEチャネルアクセストークン(長期)】',
channelSecret: process.env.LINE_CHANNEL_SECRET || '【LINEチャネルシークレット】',
};
const HELPER_BASE = process.env.HELPER_BASE || '../../helpers/';
const LineUtils = require(HELPER_BASE + 'line-utils');
const line = require('@line/bot-sdk');
const app = new LineUtils(line, config);
app.message(async (event, client) =>{
console.log(event);
var message = { type: 'text', text: event.message.text + ' ですね' };
return client.replyMessage(event.replyToken, message);
});
exports.fulfillment = app.lambda();
【LINEチャネルアクセストークン(長期)】と【LINEチャネルシークレット】のところに、先ほど覚えておいた値を付記しておきます。
LINEアプリからチャットメッセージを入力すると、 app.message()
が呼び出されます。
event.message.textに、受信したチャットメッセージがありますので、とりあえず、単純に、チャットでエコーバックするようにしておきました。
swagger: '2.0'
info:
version: 'first version'
title: Lambda Laboratory Server
paths:
/linebot:
post:
x-handler: fulfillment
parameters:
- in: body
name: body
schema:
$ref: "#/definitions/CommonRequest"
responses:
200:
description: Success
schema:
$ref: "#/definitions/CommonResponse"
Node.jsサーバを再起動します。
> node app.js
細かな処理は、api/helpers/line-utils.js で処理させています。以下のnpmモジュールを使っています。
line/line-bot-sdk-nodejs
https://github.com/line/line-bot-sdk-nodejs
LINEボットのWebhook設定
LINEデベロッパーのMessaging API設定に、Webhook設定があります。
ここに、立ち上げたNode.jsサーバのURLを指定します。以下のような感じです。
https://【Node.jsサーバのホスト名】:10443/linebot
これで、Webhookの利用をOKにして、検証ボタンを押下すると、「成功」と表示されるかと思います。
友達登録
Messaging API設定のQRコードに表示されているQRコードから、ご自身のLINEアプリでこのLINEボットを友達として登録しておきましょう。
チャットしてみましょう。エコーバックされてくるかと思います。
※タイトルがちょっと違いますが気にしないでください。。。
メッセージ応答のカスタマイズ
応答できるメッセージオブジェトの種類は以下に定義されています。
メッセージオブジェクト
https://developers.line.biz/ja/reference/messaging-api/#message-objects
・テキストメッセージ
・スタンプメッセージ
・画像メッセージ
・動画メッセージ
・音声メッセージ
・位置情報メッセージ
・イメージマップメッセージ
・テンプレートメッセージ
・Flex Message
このうち、テンプレートメッセージとFlex Message以外は名前の示す通りの単機能のメッセージなのですが、テンプレートメッセージとFlex Messageは単機能を組み合わせて定義済みのテンプレートだったり、自由に定義可能なレイアウトのメッセージです。
今回は、上記を組み合わせて、定型レイアウトを作っておきました。
・SimpleResponse
・BasicCard
・List
・Carousel
・QuickReply
以下に利用する際のソースコードを示しておきます。
'use strict';
const config = {
channelAccessToken: process.env.LINE_CHANNEL_ACCESS_TOKEN || '【LINEチャネルアクセストークン(長期)】',
channelSecret: process.env.LINE_CHANNEL_SECRET || '【LINEチャネルシークレット】',
};
const HELPER_BASE = process.env.HELPER_BASE || '../../helpers/';
const line = require('@line/bot-sdk');
const LineUtils = require(HELPER_BASE + 'line-utils');
const app = new LineUtils(line, config);
app.message(async (event, client) =>{
console.log(event);
if( event.message.text == '/' ){
var message = app.createSimpleResponse(event.message.text);
var list = [
{
title: "SimpleResponse",
action: {
type: "postback",
data: "SimpleResponse"
}
},
{
title: "BasicCard",
action: {
type: "postback",
data: "BasicCard"
}
},
{
title: "List",
action: {
type: "postback",
data: "List"
}
},
{
title: "Carousel",
action: {
type: "postback",
data: "Carousel"
}
},
];
var quickReply = app.createQuickReply(list);
message.quickReply = quickReply;
return client.replyMessage(event.replyToken, message);
}else{
var message = app.createSimpleResponse(event.message.text + ' ですね');
return client.replyMessage(event.replyToken, message);
}
});
app.postback(async (event, client) =>{
console.log(event);
if(event.postback.data == 'SimpleResponse' ){
var message = app.createSimpleResponse('SimpleResponseです');
return client.replyMessage(event.replyToken, message);
}else
if(event.postback.data == 'BasicCard' ){
var message = app.createBasicCard("BasicCard", "linebot sample", "https://scdn.line-apps.com/n/channel_devcenter/img/fx/01_1_cafe.png",
"BasicCardです", "ボタンテキスト", "ボタンを押下");
return client.replyMessage(event.replyToken, message);
}else
if(event.postback.data == 'List' ){
var list = [
{
title: "Brown Cafe",
desc: "Brown Cafeです",
image_url: "https://scdn.line-apps.com/n/channel_devcenter/img/flexsnapshot/clip/clip10.jpg",
action_text: "選択",
action: {
type: "message",
text: "Brown Cafeを選択"
}
},
{
title: "Brow&Cony's Restaurant",
desc: "Brow&Cony's Restaurantです",
image_url: "https://scdn.line-apps.com/n/channel_devcenter/img/flexsnapshot/clip/clip11.jpg",
action_text: "選択",
action: {
type: "message",
text: "Brow&Cony's Restaurantを選択"
}
},
{
title: "Tata",
desc: "Tataです",
image_url: "https://scdn.line-apps.com/n/channel_devcenter/img/flexsnapshot/clip/clip12.jpg",
action_text: "選択",
action: {
type: "message",
text: "Tataが選択されました"
}
},
];
var message = app.createList("List", list);
return client.replyMessage(event.replyToken, message);
}else
if(event.postback.data == 'Carousel' ){
var list = [
{
title: "Brown Cafe",
desc: "Brown Cafeです",
image_url: "https://scdn.line-apps.com/n/channel_devcenter/img/flexsnapshot/clip/clip10.jpg",
action_text: "選択",
action: {
type: "message",
text: "Brown Cafeを選択"
}
},
{
title: "Brow&Cony's Restaurant",
desc: "Brow&Cony's Restaurantです",
image_url: "https://scdn.line-apps.com/n/channel_devcenter/img/flexsnapshot/clip/clip11.jpg",
action_text: "選択",
action: {
type: "message",
text: "Brow&Cony's Restaurantを選択"
}
},
{
title: "Tata",
desc: "Tataです",
image_url: "https://scdn.line-apps.com/n/channel_devcenter/img/flexsnapshot/clip/clip12.jpg",
action_text: "選択",
action: {
type: "message",
text: "Tataが選択されました"
}
},
];
var message = app.createCarousel('Carousel', list);
return client.replyMessage(event.replyToken, message);
}
});
exports.fulfillment = app.lambda();
チャットメッセージで「/」(スラッシュ)を送ると、定型レイアウト名のクイックリプライが表示され、選択するとpostbackが返り、それに応じた定型レイアウトを表示する、というものです。
app.postback()
の部分がポストバックを受け取る部分です。
簡単に補足すると、以下の関数で、定型メッセージを作成し、
・SimpleResponse:app.createSimpleResponse()
・BasicCard:app.createBasicCard()
・List:app.createList()
・Carousel:app.createCarousel()
出来上がったmessageを、以下のように渡します。
return client.replyMessage(event.replyToken, message);
クイックリプライを追加する場合には、以下の関数でQuickReplyを作成し
・QuickReply:app.createQuickReply()
出来上がったquickReplyを前述のmessageに追加します。送信方法は同じです。
message.quickReply = quickReply;
SimpleResponseの例です。
BasicCardの例です。
Listの例です。
Carouselの例です。
上記は、LINEアプリからのチャットの応答としてメッセージを返信しました。一方でこちらの好きなタイミングでメッセージを送りたい場合は、replyMessageではなくpushMessageを使います。送信の際には、messageに加えて、送信先を示すLINEユーザIDが必要です。
return app.client.pushMessage('【LINEユーザID】', message);
今回は、いくつかの定型メッセージを作成しましたが、他にもLINEメッセージの仕様を参考にしたり、以下のツールを利用すれば、簡単に作成できるかと思います。
Flex Message Simulator:Flex Messageを視覚的に確認しながらメッセージを作れます。
https://developers.line.biz/flex-simulator/
LINE Bot Designer:単純なパラメータの指定でメッセージを作成できます。
https://developers.line.biz/ja/services/bot-designer/
メッセージオブジェクト:LINEの仕様です。
https://developers.line.biz/ja/reference/messaging-api/#message-objects
ESP32でLINEビーコンを作成
次は、ESP32でLINEビーコンを作成します。
まず以下のページから、LINE Simple BeaconのハードウェアIDを発行します。
LINE Official Account Manager:LINE Beacon
https://manager.line.biz/beacon/register
アカウントリストの中に、先ほど作成したMessaging APIのチャネルがあるかと思います。
それを選択し、その次の画面で表示される「ハードウェアIDを発行」ボタンを押下します。
そすると、16進数5桁のハードウェアIDが払い出されます。
Arduino IDEまたはPlatformIOのESP32のソースコードを以下に示します。
#include <M5StickC.h>
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include <BLE2902.h>
const uint8_t LINE_BEACON_HWID[] = { 0x01, 0x02, 0x03, 0x04, 0x05 }; // LINE BEACON HWID
const uint8_t LINE_BEACON_DEVICE_MESSAGE[] = { 'h', 'e', 'l', 'l', 'o' }; // LINE BEACON DEVICE MESSAGE(1-13)
#define UUID_SERVICE_SHORT 0xFE6F
#define UUID_SERVICE BLEUUID((uint16_t)UUID_SERVICE_SHORT)
BLEAdvertising *pAdvertising;
void taskServer(void*) {
BLEDevice::init("M5StickC");
BLEServer *pServer = BLEDevice::createServer();
BLEService *pService = pServer->createService(UUID_SERVICE);
pService->start();
pAdvertising = pServer->getAdvertising();
pAdvertising->addServiceUUID(UUID_SERVICE);
BLEAdvertisementData advertisementData = BLEAdvertisementData();
advertisementData.setFlags(0x06);
std::string strServiceData = "";
strServiceData += (char)0x03;
strServiceData += (char)0x03;
strServiceData += (char)0x6f;
strServiceData += (char)0xfe;
strServiceData += (char)(10 + sizeof(LINE_BEACON_DEVICE_MESSAGE));
strServiceData += (char)0x16;
strServiceData += (char)(UUID_SERVICE_SHORT & 0xff);
strServiceData += (char)((UUID_SERVICE_SHORT >> 8) & 0xff);
strServiceData += (char)0x02; // LINE Simple Beacon FrameのFrame Type
strServiceData += LINE_BEACON_HWID[0]; // LINE Simple Beacon FrameのHWID(5B)
strServiceData += LINE_BEACON_HWID[1];
strServiceData += LINE_BEACON_HWID[2];
strServiceData += LINE_BEACON_HWID[3];
strServiceData += LINE_BEACON_HWID[4];
strServiceData += (char)0x7f; // LINE Simple Beacon FrameのMeasured TxPowe
// LINE Simple Beacon FrameのDevice Message(1-13)
int i = 0;
for( i = 0 ; i < sizeof(LINE_BEACON_DEVICE_MESSAGE) ; i++ )
strServiceData += LINE_BEACON_DEVICE_MESSAGE[i];
advertisementData.addData(strServiceData);
pAdvertising->setAdvertisementData(advertisementData);
pAdvertising->start();
vTaskDelay(portMAX_DELAY); //delay(portMAX_DELAY);
}
void setup() {
M5.begin();
Serial.begin(9600);
M5.Lcd.fillScreen(BLACK);
M5.Lcd.setRotation(3);
M5.Lcd.setTextColor(WHITE);
M5.Lcd.setCursor(0, 0);
M5.Lcd.setTextSize(1);
M5.Lcd.println("[LineBeacon]");
Serial.println("LineBeacon");
xTaskCreate(taskServer, "server", 40000, NULL, 5, NULL);
}
void loop() {
M5.update();
delay(1000);
}
以下の部分を環境に合わせて書き換えてください。
・LINE BEACON HWID:LINEビーコンのハードウェアID(5バイト)
・LINE_BEACON_DEVICE_MESSAGE:LINEビーコンのDevice Message(1~13バイト)
LINE BEACON HWIDは、先ほど払い出したハードウェアIDです。
LINE_BEACON_DEVICE_MESSAGEは、自由に定義でき、指定したバイト列が、LINEボットに通知されます。指定しない場合は、1バイトの0x00を指定します。
これで、LINEアプリがインストールされたスマホが、LINEビーコンを自動的に検知し、LINEボットに知らされます。受け取れるように、以下を追記しておきます。
app.beacon( async (event, client) =>{
console.log(event);
var message = app.createSimpleResponse("ビーコン(" + event.beacon.dm + ")の受信圏内に入りました");
return client.replyMessage(event.replyToken, message);
});
app.beacon()
の部分が、LINEビーコンを検出したことを受け取る部分です。
LINEアプリ側では、以下となっている前提です。
・LINEボットがお友達として登録されている
・LINEアプリの 設定 → プライバシー管理 → 情報の提供 → LINE Beacon のチェックボックスがOnになっている
最後に
ほかにも、LINEボットに関する投稿をしていますので、参考にしてください。
Dialogflowと連携してLINE Botを作る
LINE Beaconを自宅に住まわせる
TI SensorTagをブラウザから使う(2):with LINE Things
Actions on Google向けに作ったDialogflowボットをLINEボットにする
LINEボットでゲームブックを作ってみた
LINEボットでtodoist連携
LINEボットでGoogle Alertを通知
LINEBotのリッチメニューエディタがないので自作した
LINEボットとATOM Echoでボイスメッセージを作る
以上