プログラミング初心者がLineBotをつくってみた
飲食店で働く私が、学んだプログラミングをもとに、LineBotを作成してみました。
こんな風に考えたらできた!というところや、つまづいた箇所もまとめたので、
そこも含めて、読んでいただければと思います。
コロナ禍でのデリバリー需要の増加
コロナ禍になり、UberEatsや出前館などのデリバリーをよく見るようになりました。
飲食店からすると、この委託配送ってすごく手数料が取られて、大変なんです。
ということで、自分たちで運んじゃえ!と思い、
私の働くお店でもデリバリーを始めることになりました。
事故の傾向
そうしていく中で、手探りの中でやっていたのですが、
悲しいことに、事故が頻発してしまいました。
事故が起きやすい原因の傾向が、
・夕暮れ時でライトを点けずに、車に見落とされる
・雨の日にスリップして転倒する
の2つがあります。
なので、事故を未然に防ぐために、
①日の入り時刻が分かるLineBot
②今日の天気が分かるLineBot
をつくろうと思いました。
事前準備
まずは、LineBotのアカウントをつくったりと準備が必要なのですが、
今日は割愛します。
1時間でLINE BOTを作るハンズオン (資料+レポート) in Node学園祭2017 #nodefest
こちらの記事の作ってみよう!のところが分かりやすいので、参考にご準備ください。
共通テンプレート
下記のコードをもとに、サンプル関数の部分を変えて、作成していきました。
'use strict';
// ########################################
// 初期設定など
// ########################################
// パッケージを使用します
const express = require('express');
const line = require('@line/bot-sdk');
const axios = require('axios');
// ローカル(自分のPC)でサーバーを公開するときのポート番号です
const PORT = process.env.PORT || 3000;
// Messaging APIで利用するクレデンシャル(秘匿情報)です。
const config = {
channelSecret: '作成したBotのチャネルシークレット',
channelAccessToken: '作成したBotのチャネルアクセストークン'
};
// ########## ▼▼▼ サンプル関数 ▼▼▼ ##########
(この行をサンプル関数丸ごと全部と置き換えてね)
// ########## ▲▲▲ サンプル関数 ▲▲▲ ##########
// ########################################
// LINEサーバーからのWebhookデータを処理する部分
// ########################################
// LINE SDKを初期化します
const client = new line.Client(config);
// LINEサーバーからWebhookがあると「サーバー部分」から以下の "handleEvent" という関数が呼び出されます
async function handleEvent(event) {
// 受信したWebhookが「テキストメッセージ以外」であればnullを返すことで無視します
if (event.type !== 'message' || event.message.type !== 'text') {
return Promise.resolve(null);
}
// サンプル関数を実行します
return sampleFunction(event);
}
// ########################################
// Expressによるサーバー部分
// ########################################
// expressを初期化します
const app = express();
// HTTP POSTによって '/webhook' のパスにアクセスがあったら、POSTされた内容に応じて様々な処理をします
app.post('/webhook', line.middleware(config), (req, res) => {
// 検証ボタンをクリックしたときに飛んできたWebhookを受信したときのみ以下のif文内を実行
if (req.body.events.length === 0) {
res.send('Hello LINE BOT! (HTTP POST)'); // LINEサーバーに返答します(なくてもよい)
console.log('検証イベントを受信しました!'); // ターミナルに表示します
return; // これより下は実行されません
} else {
// 通常のメッセージなど … Webhookの中身を確認用にターミナルに表示します
console.log('受信しました:', req.body.events);
}
// あらかじめ宣言しておいた "handleEvent" 関数にWebhookの中身を渡して処理してもらい、
// 関数から戻ってきたデータをそのままLINEサーバーに「レスポンス」として返します
Promise.all(req.body.events.map(handleEvent)).then((result) => res.json(result));
});
// 最初に決めたポート番号でサーバーをPC内だけに公開します
// (環境によってはローカルネットワーク内にも公開されます)
app.listen(PORT);
console.log(`ポート${PORT}番でExpressサーバーを実行中です…`);
①日の入り時刻が分かるLineBot
最初に教えてもらったコードが大阪府北区の日の出を調べるコードでした。
Sunset and sunrise times APIを利用しています。
日の出を調べる
const sampleFunction = async (event) => {
// ユーザーメッセージが「日の出」か「日の入り」かどうか
if (event.message.text !== '今日の日の出は?') {
return client.replyMessage(event.replyToken, {
type: 'text',
text: '「今日の日の出は?」と話しかけてね'
});
} else {
// 「リプライ」を使って先に返事しておきます
await client.replyMessage(event.replyToken, {
type: 'text',
text: '調べています……'
});
let pushText = '';
try {
// axiosで日の出日の入り時刻のAPIを叩きます(少し時間がかかる・ブロッキングする)
const res = await axios.get('https://api.sunrise-sunset.org/json?lat=34.6959484&lng=135.4927352');
// 取得できるのはUTCなので日本時間(+9時間)になおす
const utc_time = res.data.results.sunrise;
// '時', '分', '秒 PM' に分割する
const tm_split = utc_time.split(':');
// '時' を9時間進めて12時間戻す(13時を過ぎないようにする)
const jp_hour = Number(tm_split[0]) + 9 - 12;
// '秒 PM' を '秒' だけにする
const sec = tm_split[2].split(' ')[0];
// 再構成する
const time_string = `${jp_hour}時${tm_split[1]}分${sec}秒`;
pushText = `今日の大阪市北区付近の日の出は${time_string}です!`;
} catch (error) {
pushText = '検索中にエラーが発生しました。ごめんね。';
// APIからエラーが返ってきたらターミナルに表示する
console.error(error);
}
// 「プッシュ」で後からユーザーに通知します
return client.pushMessage(event.source.userId, {
type: 'text',
text: pushText,
});
}
};
ちょっと工夫
このコードを見て、
1)lat=34.6959484&lng=135.4927352'
の緯度と経度変えれば行けるんじゃないか?
2)日の出
の部分は全部日の入り
に変えちゃえ!
3)const utc_time = res.data.results.sunrise;
のsunriseをsunset
に変えたら行けるんじゃないか?
と思い、書き換えたコードがこちら!
日の入りを調べる
const sampleFunction = async (event) => {
// ユーザーメッセージが「日の出」か「日の入り」かどうか
if (event.message.text !== '今日の日の入りは?') {
return client.replyMessage(event.replyToken, {
type: 'text',
text: '「今日の日の入りは?」と話しかけてね'
});
} else {
// 「リプライ」を使って先に返事しておきます
await client.replyMessage(event.replyToken, {
type: 'text',
text: '調べています……'
});
let pushText = '';
try {
// axiosで日の出日の入り時刻のAPIを叩きます(少し時間がかかる・ブロッキングする)
const res = await axios.get('https://api.sunrise-sunset.org/json?lat=35.536325&lng=139.635307');
// 取得できるのはUTCなので日本時間(+9時間)になおす
const utc_time = res.data.results.sunset;
// '時', '分', '秒 PM' に分割する
const tm_split = utc_time.split(':');
// '時' を9時間進めて12時間戻す(13時を過ぎないようにする)
const jp_hour = Number(tm_split[0]) + 9 - 12;
// '秒 PM' を '秒' だけにする
const sec = tm_split[2].split(' ')[0];
// 再構成する
const time_string = `${jp_hour}時${tm_split[1]}分${sec}秒`;
pushText = `今日の綱島付近の日の入りは${time_string}です!ライトをつけてくださいね!`;
} catch (error) {
pushText = '検索中にエラーが発生しました。ごめんね。';
// APIからエラーが返ってきたらターミナルに表示する
console.error(error);
}
// 「プッシュ」で後からユーザーに通知します
return client.pushMessage(event.source.userId, {
type: 'text',
text: pushText,
});
}
};
②今日の天気が分かるLineBot
こちらの記事を参考に作成しました。
1時間でLINE BOTを作るハンズオン (資料+レポート) in Node学園祭2017 #nodefest
APIはこちらです
https://weather.tsukumijima.net/
天気を調べる
const sampleFunction = async (event) => {
if (event.message.text !== '今日の天気は?') {
return client.replyMessage(event.replyToken, {
type: 'text',
text: '「今日の天気は?」と話しかけてね'
});
}
let replyText = '';
replyText = 'ちょっと待ってね'; //"ちょっと待ってね"ってメッセージだけ先に処理
await client.replyMessage(event.replyToken, {
type: 'text',
text: replyText
});
//axiosを使って天気APIにアクセス
const CITY_ID = `140010`; //取得したい地域のIDを指定
const URL = `https://weather.tsukumijima.net/api/forecast?city=${CITY_ID}`;
const res = await axios.get(URL);
const pushText = res.data.description.text;
return client.pushMessage(event.source.userId, {
type: 'text',
text: pushText,
});
}
つまづいたところ
1)CITY_ID
を変えておらず、神奈川県の天気にできなかった。
2)参考記事では最初がasync function handleEvent(event) {
になっていたが、
共通テンプレートでは最後にreturn sampleFunction(event);
でサンプル関数を実行しているので、
const sampleFunction = async (event) => {
で始める必要があった。
全体を通してつまづいたところ
初心者の私が全体を通してつまづいたところが、
ngrokを立ち上げるたびに、URLが変わるので、webhookは毎回更新する!!
ということです。
オウム返しが返ってこないとか、上手く動いてない・・・となったら、まずはここを確認して見てください。
まとめ
同じBot内で日の入りと天気の両方が聞けたらよかったのですが、
結果はバラバラのBotでないと動かない形になりました。
また、位置情報を送ったら、そこから日の入りと天気が返ってくるというところまでできたら、
どんなお店でも使えるので最高だなと思いました。
(まだまだそこまでは行きつかない現実・・・)
でも、自分が調べたいことに対して、しっかりとBotで返ってくるので、自分の中では大満足です◎
これからも頑張って、勉強するぞー!!