位置情報を送ると天気予報を教えてくれるLINE botを作成してみました。
Livedoor社の提供している天気情報APIを利用しています。
BOTの名前はweとweatherとtogetherをもじって、
"we-together"にしました。
現在地の天気予報を確認したい場合や、LINEグループを作成した上で誰かと旅行の予定などを立てる際に役立つかも知れません。
DBを使用せずにかなり無茶な形での開発した結果として
DBの存在の有難みを肌身で痛感し、DBの勉強意欲が猛烈に向上しています、笑
今回参考にしたのはこちらの記事です。
#環境
- Windows 10
- Node.js 12.16.1
#事前設定
この記事をもとに事前設定を行っています。
#開発
LINEの位置情報には次の情報があります。
- 緯度(atitude)と経緯(longitude)
- アドレス(address)
東京ディズニーランドのLINE位置情報
[
{
type: 'message',
replyToken: 'cc93a3636cf54f218a924f63ab308d83',
source: { userId: 'hogehoge', type: 'user' },
timestamp: 1585812598044,
mode: 'active',
message: {
type: 'location',
id: '11711207573900',
title: '東京ディズニーリゾート',
address: '舞浜1-1 浦安市, 千葉県 279-8511 日本',
latitude: 35.630668,
longitude: 139.882873
}
}
]
latitude: 35.630668,
longitude: 139.882873
address: '舞浜1-1 浦安市, 千葉県 279-8511 日本'
いま考えると、緯度(atitude)と経緯(longitude)を使用してAPI連携した方がより正確な天気情報が取得できたのだと思いますが、
今回はアドレス(address)のテキスト情報を使用して開発しています。
###開発コード
'use strict';
const express = require('express');
const line = require('@line/bot-sdk');
const axios = require('axios');
const PORT = process.env.PORT || 3000;
const config = {
channelAccessToken: '',
channelSecret: ''
};
const app = express();
app.post('/webhook', line.middleware(config), (req, res) => {
console.log(req.body.events);
Promise
.all(req.body.events.map(handleEvent))
.then((result) => res.json(result));
});
const client = new line.Client(config);
function handleEvent(event) {
if (event.type !== 'message' || event.message.type !== 'location') {
return Promise.resolve(null);
}
let mes = ''
if(event.message.type === 'location'){
mes = '天気を確認しますね'; //メッセージだけ先に処理
getNodeVer(event.source.userId,event.message.address); //スクレイピング処理が終わったらプッシュメッセージ
}else{
mes = event.message.text;
}
return client.replyMessage(event.replyToken, {
type: 'text',
text: mes
});
}
const getNodeVer = async (userId, address) => {
let city_id = '260010';
console.log("address : " + address);
// 無茶苦茶、強引な検索
if(address.indexOf("東京") > -1){
city_id = '130010'; // 東京
} else if(address.indexOf("千葉") > -1){
city_id = '120010'; // 千葉
}
const res = await axios.get('http://weather.livedoor.com/forecast/webservice/json/v1?city=' + city_id);
const item = res.data;
await client.pushMessage(userId, {
type: 'text',
text: item.description.text,
});
}
app.listen(PORT);
console.log(`Server running at ${PORT}`);
###説明
以下で、位置情報のアドレスに"千葉"という文言が1件でもあれば、
"120010"(city_id)を取得
if(address.indexOf("千葉") > -1){
city_id = '120010'; // 千葉
取得したcity_idを用いて以下で
const res = await axios.get('http://weather.livedoor.com/forecast/webservice/json/v1?city=' + city_id);
http://weather.livedoor.com/forecast/webservice/json/v1?city=120010
という形にして、
そこから必要な天気情報を取得しています。
東京や千葉のケースで、送った位置情報をもとに天気情報を教えてくれました。
ただ、今のこの状態だと東京と千葉しか対応できていないので、
全国に対応できるように142件地域別に分岐を作りました。(通常はDB管理すべきです。。)
###条件分岐追加
console.log("address : " + address);
// 無茶苦茶、強引な検索
if(address.indexOf("稚内") > -1){city_id = '011000'; // 稚内
} else if(address.indexOf("旭川") > -1){city_id = '012010'; // 旭川
} else if(address.indexOf("留萌") > -1){city_id = '012020'; // 留萌
} else if(address.indexOf("網走") > -1){city_id = '013010'; // 網走
} else if(address.indexOf("北見") > -1){city_id = '013020'; // 北見
} else if(address.indexOf("紋別") > -1){city_id = '013030'; // 紋別
} else if(address.indexOf("根室") > -1){city_id = '014010'; // 根室
} else if(address.indexOf("釧路") > -1){city_id = '014020'; // 釧路
} else if(address.indexOf("帯広") > -1){city_id = '014030'; // 帯広
} else if(address.indexOf("室蘭") > -1){city_id = '015010'; // 室蘭
} else if(address.indexOf("浦河") > -1){city_id = '015020'; // 浦河
} else if(address.indexOf("札幌") > -1){city_id = '016010'; // 札幌
} else if(address.indexOf("岩見沢") > -1){city_id = '016020'; // 岩見沢
} else if(address.indexOf("倶知安") > -1){city_id = '016030'; // 倶知安
} else if(address.indexOf("函館") > -1){city_id = '017010'; // 函館
} else if(address.indexOf("江差") > -1){city_id = '017020'; // 江差
} else if(address.indexOf("青森") > -1){city_id = '020010'; // 青森
} else if(address.indexOf("むつ") > -1){city_id = '020020'; // むつ
} else if(address.indexOf("八戸") > -1){city_id = '020030'; // 八戸
} else if(address.indexOf("盛岡") > -1){city_id = '030010'; // 盛岡
} else if(address.indexOf("宮古") > -1){city_id = '030020'; // 宮古
} else if(address.indexOf("大船渡") > -1){city_id = '030030'; // 大船渡
} else if(address.indexOf("仙台") > -1){city_id = '040010'; // 仙台
} else if(address.indexOf("白石") > -1){city_id = '040020'; // 白石
} else if(address.indexOf("秋田") > -1){city_id = '050010'; // 秋田
} else if(address.indexOf("横手") > -1){city_id = '050020'; // 横手
} else if(address.indexOf("山形") > -1){city_id = '060010'; // 山形
} else if(address.indexOf("米沢") > -1){city_id = '060020'; // 米沢
} else if(address.indexOf("酒田") > -1){city_id = '060030'; // 酒田
} else if(address.indexOf("新庄") > -1){city_id = '060040'; // 新庄
} else if(address.indexOf("福島") > -1){city_id = '070010'; // 福島
} else if(address.indexOf("小名浜") > -1){city_id = '070020'; // 小名浜
} else if(address.indexOf("若松") > -1){city_id = '070030'; // 若松
} else if(address.indexOf("水戸") > -1){city_id = '080010'; // 水戸
} else if(address.indexOf("土浦") > -1){city_id = '080020'; // 土浦
} else if(address.indexOf("宇都宮") > -1){city_id = '090010'; // 宇都宮
} else if(address.indexOf("大田原") > -1){city_id = '090020'; // 大田原
} else if(address.indexOf("前橋") > -1){city_id = '100010'; // 前橋
} else if(address.indexOf("みなかみ") > -1){city_id = '100020'; // みなかみ
} else if(address.indexOf("さいたま") > -1){city_id = '110010'; // さいたま
} else if(address.indexOf("熊谷") > -1){city_id = '110020'; // 熊谷
} else if(address.indexOf("秩父") > -1){city_id = '110030'; // 秩父
} else if(address.indexOf("千葉") > -1){city_id = '120010'; // 千葉
} else if(address.indexOf("銚子") > -1){city_id = '120020'; // 銚子
} else if(address.indexOf("館山") > -1){city_id = '120030'; // 館山
} else if(address.indexOf("東京") > -1){city_id = '130010'; // 東京
} else if(address.indexOf("大島") > -1){city_id = '130020'; // 大島
} else if(address.indexOf("八丈島") > -1){city_id = '130030'; // 八丈島
} else if(address.indexOf("父島") > -1){city_id = '130040'; // 父島
} else if(address.indexOf("横浜") > -1){city_id = '140010'; // 横浜
} else if(address.indexOf("小田原") > -1){city_id = '140020'; // 小田原
} else if(address.indexOf("新潟") > -1){city_id = '150010'; // 新潟
} else if(address.indexOf("長岡") > -1){city_id = '150020'; // 長岡
} else if(address.indexOf("高田") > -1){city_id = '150030'; // 高田
} else if(address.indexOf("相川") > -1){city_id = '150040'; // 相川
} else if(address.indexOf("富山") > -1){city_id = '160010'; // 富山
} else if(address.indexOf("伏木") > -1){city_id = '160020'; // 伏木
} else if(address.indexOf("金沢") > -1){city_id = '170010'; // 金沢
} else if(address.indexOf("輪島") > -1){city_id = '170020'; // 輪島
} else if(address.indexOf("福井") > -1){city_id = '180010'; // 福井
} else if(address.indexOf("敦賀") > -1){city_id = '180020'; // 敦賀
} else if(address.indexOf("甲府") > -1){city_id = '190010'; // 甲府
} else if(address.indexOf("河口湖") > -1){city_id = '190020'; // 河口湖
} else if(address.indexOf("長野") > -1){city_id = '200010'; // 長野
} else if(address.indexOf("松本") > -1){city_id = '200020'; // 松本
} else if(address.indexOf("飯田") > -1){city_id = '200030'; // 飯田
} else if(address.indexOf("岐阜") > -1){city_id = '210010'; // 岐阜
} else if(address.indexOf("高山") > -1){city_id = '210020'; // 高山
} else if(address.indexOf("静岡") > -1){city_id = '220010'; // 静岡
} else if(address.indexOf("網代") > -1){city_id = '220020'; // 網代
} else if(address.indexOf("三島") > -1){city_id = '220030'; // 三島
} else if(address.indexOf("浜松") > -1){city_id = '220040'; // 浜松
} else if(address.indexOf("名古屋") > -1){city_id = '230010'; // 名古屋
} else if(address.indexOf("豊橋") > -1){city_id = '230020'; // 豊橋
} else if(address.indexOf("津") > -1){city_id = '240010'; // 津
} else if(address.indexOf("尾鷲") > -1){city_id = '240020'; // 尾鷲
} else if(address.indexOf("大津") > -1){city_id = '250010'; // 大津
} else if(address.indexOf("彦根") > -1){city_id = '250020'; // 彦根
} else if(address.indexOf("京都") > -1){city_id = '260010'; // 京都
} else if(address.indexOf("舞鶴") > -1){city_id = '260020'; // 舞鶴
} else if(address.indexOf("大阪") > -1){city_id = '270000'; // 大阪
} else if(address.indexOf("神戸") > -1){city_id = '280010'; // 神戸
} else if(address.indexOf("豊岡") > -1){city_id = '280020'; // 豊岡
} else if(address.indexOf("奈良") > -1){city_id = '290010'; // 奈良
} else if(address.indexOf("風屋") > -1){city_id = '290020'; // 風屋
} else if(address.indexOf("和歌山") > -1){city_id = '300010'; // 和歌山
} else if(address.indexOf("潮岬") > -1){city_id = '300020'; // 潮岬
} else if(address.indexOf("鳥取") > -1){city_id = '310010'; // 鳥取
} else if(address.indexOf("米子") > -1){city_id = '310020'; // 米子
} else if(address.indexOf("松江") > -1){city_id = '320010'; // 松江
} else if(address.indexOf("浜田") > -1){city_id = '320020'; // 浜田
} else if(address.indexOf("西郷") > -1){city_id = '320030'; // 西郷
} else if(address.indexOf("岡山") > -1){city_id = '330010'; // 岡山
} else if(address.indexOf("津山") > -1){city_id = '330020'; // 津山
} else if(address.indexOf("広島") > -1){city_id = '340010'; // 広島
} else if(address.indexOf("庄原") > -1){city_id = '340020'; // 庄原
} else if(address.indexOf("下関") > -1){city_id = '350010'; // 下関
} else if(address.indexOf("山口") > -1){city_id = '350020'; // 山口
} else if(address.indexOf("柳井") > -1){city_id = '350030'; // 柳井
} else if(address.indexOf("萩") > -1){city_id = '350040'; // 萩
} else if(address.indexOf("徳島") > -1){city_id = '360010'; // 徳島
} else if(address.indexOf("日和佐") > -1){city_id = '360020'; // 日和佐
} else if(address.indexOf("高松") > -1){city_id = '370000'; // 高松
} else if(address.indexOf("松山") > -1){city_id = '380010'; // 松山
} else if(address.indexOf("新居浜") > -1){city_id = '380020'; // 新居浜
} else if(address.indexOf("宇和島") > -1){city_id = '380030'; // 宇和島
} else if(address.indexOf("高知") > -1){city_id = '390010'; // 高知
} else if(address.indexOf("室戸岬") > -1){city_id = '390020'; // 室戸岬
} else if(address.indexOf("清水") > -1){city_id = '390030'; // 清水
} else if(address.indexOf("福岡") > -1){city_id = '400010'; // 福岡
} else if(address.indexOf("八幡") > -1){city_id = '400020'; // 八幡
} else if(address.indexOf("飯塚") > -1){city_id = '400030'; // 飯塚
} else if(address.indexOf("久留米") > -1){city_id = '400040'; // 久留米
} else if(address.indexOf("佐賀") > -1){city_id = '410010'; // 佐賀
} else if(address.indexOf("伊万里") > -1){city_id = '410020'; // 伊万里
} else if(address.indexOf("長崎") > -1){city_id = '420010'; // 長崎
} else if(address.indexOf("佐世保") > -1){city_id = '420020'; // 佐世保
} else if(address.indexOf("厳原") > -1){city_id = '420030'; // 厳原
} else if(address.indexOf("福江") > -1){city_id = '420040'; // 福江
} else if(address.indexOf("熊本") > -1){city_id = '430010'; // 熊本
} else if(address.indexOf("阿蘇乙姫") > -1){city_id = '430020'; // 阿蘇乙姫
} else if(address.indexOf("牛深") > -1){city_id = '430030'; // 牛深
} else if(address.indexOf("人吉") > -1){city_id = '430040'; // 人吉
} else if(address.indexOf("大分") > -1){city_id = '440010'; // 大分
} else if(address.indexOf("中津") > -1){city_id = '440020'; // 中津
} else if(address.indexOf("日田") > -1){city_id = '440030'; // 日田
} else if(address.indexOf("佐伯") > -1){city_id = '440040'; // 佐伯
} else if(address.indexOf("宮崎") > -1){city_id = '450010'; // 宮崎
} else if(address.indexOf("延岡") > -1){city_id = '450020'; // 延岡
} else if(address.indexOf("都城") > -1){city_id = '450030'; // 都城
} else if(address.indexOf("高千穂") > -1){city_id = '450040'; // 高千穂
} else if(address.indexOf("鹿児島") > -1){city_id = '460010'; // 鹿児島
} else if(address.indexOf("鹿屋") > -1){city_id = '460020'; // 鹿屋
} else if(address.indexOf("種子島") > -1){city_id = '460030'; // 種子島
} else if(address.indexOf("名瀬") > -1){city_id = '460040'; // 名瀬
} else if(address.indexOf("那覇") > -1){city_id = '471010'; // 那覇
} else if(address.indexOf("名護") > -1){city_id = '471020'; // 名護
} else if(address.indexOf("久米島") > -1){city_id = '471030'; // 久米島
} else if(address.indexOf("南大東") > -1){city_id = '472000'; // 南大東
} else if(address.indexOf("宮古島") > -1){city_id = '473000'; // 宮古島
} else if(address.indexOf("石垣島") > -1){city_id = '474010'; // 石垣島
} else if(address.indexOf("与那国島") > -1){city_id = '474020'; // 与那国島
}
const res = await axios.get('http://weather.livedoor.com/forecast/webservice/json/v1?city=' + city_id);
const item = res.data;
これで初めて全国に対応できるようになりました
那覇(那覇空港辺りでテスト)
#終わりに
- データベースと接続できるような開発にもチャレンジします!
- 開発して分かりましたが、特定のケースではLINE位置情報のアドレスが郵便番号だけということもあり、必ずしも地域の文言を含むわけではないようです。また、端末の言語設定にも依存しますので、もし仮に、この機能をブラッシュアップするのであれば、緯度(atitude)と経緯(longitude)を使用してAPI連携する形で作り直した方が良いと思いました。