こんにちは、エンジニアのさもです。
前回は、何かテキストを送ると名言を返してくれるBotを作りました。
今回はその続編で、位置情報を送ると標高を返してくれるBotを作りました。 (注:Lineで現在地を送るにはスマホからしかできないっぽいです)
スポンサーリンク
はじめに
前回の続編なので、Botを作るまでの準備(チャンネルの登録やオウム返しBotが実装済みであること)が出来ている前提とします。
Rails版のオウム返しBotの実装例は以下に書いています。
実装
API
今回はこちらのAPIを利用させてもらいます。
経度、緯度を送ると標高などの情報がxml形式で帰ってきます。
利用方法は、Line経由で送られてきた位置情報から経度、緯度を取り出し、
http://lab.uribou.net/ll2h/?ll=緯度,経度
へrubyでアクセスします。
コントローラの実装
githubで紹介されているのはsinatraを使うことを想定しているので、 まずは、オウム返しBotのRails版を書いておきます。
チャンネルシークレットと、アクセストークンはチャンネル登録で取っておいたものを書いてください。
今回は簡単のためソースに書いていますが、実際は環境変数に書いておき、それを取ってくるようにしてください。
require 'line/bot' class WebhookController < ApplicationController protect_from_forgery with: :null_session before_action :set_line_client CHANNEL_SECRET = '自分のCHANNEL_SECRET' CHANNEL_ACCESS_TOKEN = '自分のアクセストークン' def callback body = request.body.read unless @client.validate_signature(body, request.env['HTTP_X_LINE_SIGNATURE']) error 400 do 'Bad Request' end end event = @client.parse_events_from(body)[0] case event.type when "text" message = { type: 'text', text: event.message['text'] } else message = { type: 'text', text: "メッセージを送ってね" } end @client.reply_message(event['replyToken'], message) render :nothing => true, status: :ok end private def set_line_client @client ||= Line::Bot::Client.new { |config| config.channel_secret = CHANNEL_SECRET config.channel_token = CHANNEL_ACCESS_TOKEN } end end
それでは、このコードに位置情報が送られてきたら標高を返す処理を追加していきます。
- ライブラリの追加
APIを利用するために、require 'open-uri'
、xml解析のためにrequire 'rexml/document'
をrequire 'line/bot'
の下の行に追加します
- caseにメッセージタイプが位置情報だったときの処理を追加します
when "location" message = { type: 'text', text: return_location_height(event.message) }
return_location_heightが実際に返すメッセージを組み立てるメソッドです。
- return_location_heightの実装
位置情報は以下のフォーマットで送られてきます
{ "type": "location", "title": "my location", "address": "〒150-0002 東京都渋谷区渋谷2丁目21−1", "latitude": 35.65910807942215, "longitude": 139.70372892916203 }
ここで最低限必要なのは、緯度(latitude)と経度(longitude)です。あとは住所なんかを表示させたいのでaddressもとっておきます。
def return_location_height(message) ret_msg = message['address'] + "の標高は" lat = message['latitude'] lon = message['longitude'] body = open("http://lab.uribou.net/ll2h/?ll=#{lat},#{lon}", &:read) doc = REXML::Document.new(body) ret_msg += doc.elements['result/height'].text + "mです" ret_msg end
open("http://lab.uribou.net/ll2h/?ll=#{lat},#{lon}", &:read)
の結果は以下のようなxmlです。
<result> <version>0.1</version> <error>0</error> <coordinate><lat>35.681</lat><lng>139.767</lng></coordinate> <height>11.87</height> <unit>m</unit> <dem>SRTM3</dem> </result>
REXML::Document
を使えば、階層構造になっているxmlをdoc.elements['result/height']
のように直感的にアクセスすることが出来ます。
もうxml怖くない!
最終的には、以下のようなコードになります
require 'line/bot' require 'open-uri' require 'rexml/document' class WebhookController < ApplicationController protect_from_forgery with: :null_session before_action :set_line_client CHANNEL_SECRET = '自分のCHANNEL_SECRET' CHANNEL_ACCESS_TOKEN = '自分のアクセストークン' def callback body = request.body.read unless @client.validate_signature(body, request.env['HTTP_X_LINE_SIGNATURE']) error 400 do 'Bad Request' end end event = @client.parse_events_from(body)[0] case event.type when "text" message = { type: 'text', text: return_message } when "location" message = { type: 'text', text: return_location_height(event.message) } else message = { type: 'text', text: "メッセージか位置情報を送ってね" } end @client.reply_message(event['replyToken'], message) render :nothing => true, status: :ok end private def return_message open("http://www.meigensyu.com/quotations/view/random") do |file| page = file.read page.scan(/<div class=\"text\">(.*?)<\/div>/).each do |meigen| return meigen[0].encode("sjis") end end end def return_location_height(message) ret_msg = message['address'] + "の標高は" lat = message['latitude'] lon = message['longitude'] body = open("http://lab.uribou.net/ll2h/?ll=#{lat},#{lon}", &:read) doc = REXML::Document.new(body) ret_msg += doc.elements['result/height'].text + "mです" ret_msg end def set_line_client @client ||= Line::Bot::Client.new { |config| config.channel_secret = CHANNEL_SECRET config.channel_token = CHANNEL_ACCESS_TOKEN } end end
実行例
- まずbot君との画面で、下の赤枠のボタンを押します
- 次に、下の画像の赤枠で囲んである「+」ボタンを押します
- 位置情報というボタンがあるので、押します。
LineにGPSを許可している場合は、地図と、自分のいる位置が表示されるので、自分の位置をタップします。
- すると、位置情報が送られて、標高が返ってきます
最後に
オウム返しBotを応用して標高を返すBotを作ってみました。
山とかで使うと面白そうですね。
サーバに送られてきさいすれば、webエンジニアの領域なので、もっと複雑なことも出来そうです。
以上、現在地の標高を教えてくれるLineBot作ったでした。
読者登録をしていただけると、ブログを続ける励みになりますので、よろしくお願いします。