Posted at

山の天気を教えてくれるLinebotを作る on Heroku(Freeプラン)

登山仲間と登山に行くときに天気をググってURLをLineグループで共有することがよくあるので、少しでも手順を簡略化するために山の天気を教えてくれるLinebotを作ることにしました。

※注意

この記事ではHerokuやLINE Developersを使っています。

HerokuやLINE Developersは次々に仕様が変わっていくので料金など重要な情報は公式情報を確認するようにしてください。


仕様

Lineで「○○山 天気」とコメントすると、Linebotがその山の天気予報ページをコメントしてくれる。

botがコメントする天気ページは下記の「てんきとくらす」を使っています。山の天気がわかるので大変お世話になっているサイトです。

サイトポリシーに『・本サイトへのリンクは原則自由であり、事前連絡も必要ありません。』と書いてあるので堂々と使って大丈夫でしょう。

https://tenkura.n-kishou.co.jp/tk/policy.html


システム構成

システム構成は下記の通りです。

スクリーンショット 2019-07-25 14.45.51.png


インフラ

Lineメッセージを解析して該当の天気URLを返却するAPIサーバーは、1アプリを動かすだけであれば料金がかからないherokuのFreeプランを使うことにしました。

DBも10,000行までであれば無料で使えます。

(※2019年7月時点)

https://jp.heroku.com/pricing


Line Developers

Linebotを作るにはLine Developersに登録する必要があります。

https://developers.line.biz/

登録方法は下記記事と同じなのでこの記事では省略します。

GCPを使って日次のLine push通知を作ってみた

上記の他にWebhookの設定が必要ですが、それはherokuの環境構築ができた後に設定するので後述します。


開発環境

Ruby on Railsで開発しました。

DBはherokuにあわせてpostgres。

ソース管理はheroku内のgithubを使うこともできるが、自分のgithubで管理したかったので自分のgithub経由でherokuへデプロイするようにしました。

開発環境ではdockerを使っています。


開発


開発環境構築

Dockerを使って開発環境を構築します。

最初にDockerfile, docker-compose.yml, Gemfile, Gemfile.lockを作成します。


Dockerfile

FROM ruby:2.6.3

RUN curl -sL https://deb.nodesource.com/setup_10.x | bash -
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
RUN apt-get update -qq && apt-get install -y build-essential nodejs yarn postgresql-client

RUN mkdir -p /app
WORKDIR /app

COPY Gemfile Gemfile.lock ./

RUN gem update bundler
RUN bundle install
COPY . .

CMD ["rails", "server", "-b", "0.0.0.0"]



docker-compose.yml

version: '3'

services:
web:
build: .
command: bundle exec rails s -p 3000 -b '0.0.0.0'
environment:
DATABASE_HOST: db
DATABASE_PORT: 5432
DATABASE_USER: postgres
DATABASE_PASSWORD:
links:
- db
volumes:
- .:/app
ports:
- 3000:3000
tty: true
stdin_open: true
db:
image: postgres:11.3
ports:
- "5432"
volumes:
- db-volume:/var/lib/postgresvolumes
volumes:
db-volume:

Railsのバージョンはなんでもよかったので現時点で最新の6にしてみた。


Gemfile

source 'https://rubygems.org'

gem 'rails', '6.0.0.rc1'


Gemfile.lockは空

ファイルが準備できたらdocker上にrails環境を構築します。

まずは環境をビルドします。

# build

docker-compose build

続いてdocker上にrails環境を生成します。

# rails new

docker-compose run web bundle exec rails new . --database=postgresql --skip-test

データベースの設定を行います。

development, test環境のアカウントは適当にpostgres/passwordにしました。(環境変数で変更もできます)

productionはherokuで発行されるurlを環境変数DATABASE_URLで指定できるようにしています。


config/database.yml

default: &default

adapter: postgresql
encoding: unicode
development:
<<: *default
database: db_development
host: <%= ENV.fetch('DATABASE_HOST') { 'localhost' } %>
port: <%= ENV.fetch('DATABASE_PORT') { 5432 } %>
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: <%= ENV.fetch('DATABASE_USER') { 'postgres' } %>
password: <%= ENV.fetch('DATABASE_PASSWORD') { 'password' } %>
test:
<<: *default
database: db_test
host: <%= ENV.fetch('DATABASE_HOST') { 'localhost' } %>
port: <%= ENV.fetch('DATABASE_PORT') { 5432 } %>
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: <%= ENV.fetch('DATABASE_USER') { 'postgres' } %>
password: <%= ENV.fetch('DATABASE_PASSWORD') { 'password' } %>
production:
<<: *default
url: <%= ENV['DATABASE_URL'] %>
database: db_production

rails環境の準備ができたのでサーバーを起動します。

# サーバー起動(docker-composeのcommandをバックグランドで起動)

docker-compose up --build -d

http://localhost:3000/ で接続確認。

下記が表示されれば疎通OKです。

スクリーンショット 2019-07-25 14.59.37.png


実装

line-botを実装します。

rubyで実装する場合、'line-bot-api'というgemを使うと良いです。

githubにLinebotのサンプルもあるので参考にして作りました。sinatraを使っているのでRailsで作る場合は少し読み替える必要はあります。

https://github.com/line/line-bot-sdk-ruby

私は下記のように実装しました。基本、サンプルと同じように作っています。


config/routes.rb

  post '/callback' => 'linebot#callback'



app/models/yama.rb

#

# yamasテーブルに山の名称(name)、URLを作るためのcode、typeを保持しています。
#
class Yama < ApplicationRecord
self.inheritance_column = :_type_disabled

class << self
def find_by_message(message)
# あんまりイケてないけど全部の山の名称を1件ずつメッセージに含まれているか確認して
# 含まれていたらその山情報を返却する。
# 本当は全文検索とかした方が良いと思うけどデータ数少なくてこれでも困っていないのでとりあえずこれで;;
all.find_each do |yama|
return yama if message =~ /#{yama.name}/
end
end
end

def url
"https://tenkura.n-kishou.co.jp/tk/kanko/kad.html?code=#{code}&type=#{type}&ba=hk"
end
end



app/controllers/linebot_controller.rb

class LinebotController < ApplicationController

require 'line/bot'

protect_from_forgery except: [:callback]

def callback
body = request.body.read

signature = request.env['HTTP_X_LINE_SIGNATURE']
unless client.validate_signature(body, signature)
head :bad_request
return
end

events = client.parse_events_from(body)

events.each { |event|
case event
when Line::Bot::Event::Message
case event.type
when Line::Bot::Event::MessageType::Text
# メッセージに"天気"という文字が入っているか確認。入っていなければSKIP
next unless event.message['text'] =~ /天気/

if yama = Yama.find_by_message(event.message['text'])
# 山が見つかればメッセージを生成してreplyする
reply_text = "#{yama.name}の天気\n#{yama.url}"
message = {
type: 'text',
text: reply_text
}
client.reply_message(event['replyToken'], message)
end
end
end
}

head :ok
end

private

def client
@client ||= Line::Bot::Client.new do |config|
config.channel_secret = ENV["LINE_CHANNEL_SECRET"]
config.channel_token = ENV["LINE_CHANNEL_TOKEN"]
end
end
end


実装が終わったら自身のgithubへPushしましょう。


heroku


環境構築


app新規作成

herokuのdashboardを開き、"Create new app"を選択します。

スクリーンショット 2019-08-01 14.43.41.png

適当な名前をつけてappを作成します。

スクリーンショット 2019-08-01 14.43.20.png


Deployタブ

Deployment methodで"GitHub"を選択して、Connect to GitHubで先ほどpushしたリポジトリを選択します。

スクリーンショット 2019-08-01 14.45.46.png


Resourcesタブ

Add-onesで"Heroku Postgres"を検索して選択します。

スクリーンショット 2019-08-01 14.52.00.png

Hobby Dev-Freeを選択して、Provision

スクリーンショット 2019-08-01 14.53.16.png

これでpostgresが利用できます。

念のため、同ページに記載されているEstimated Monthly Costが$0.00(費用がかかっていない)ことも確認しておきましょう。

スクリーンショット 2019-08-01 14.55.38.png


Postgres

先ほど作成したHeroku PostgresがリンクになっているのでそこをクリックしてPostgresの情報を確認します。

リンク先のSettingsタブにDatabase Credentialsという項目があるのでView Credentials...をクリックします。

その中に表示される"URI"をDB接続で利用します。

スクリーンショット 2019-08-01 14.58.45.png


Settingsタブ

SettingsタブのConfig Varsに必要な環境変数を足します。

DATABASE_URLはすでに設定されていると思いますが、もしなければ先ほど確認したpostgresのURIを設定します。

LINE_CHANNEL_SECRET、LINE_CHANNEL_TOKENはLineDevelopersで作成したチャンネルページに記載されているものを設定します。(LINE_CHANNEL_TOKENはLINE Developersのアクセストークンのことです)

あとはRailsで必要な諸々の環境変数を設定します。

スクリーンショット 2019-08-01 15.04.20.png

同じタブに"Domains and certificates"にURLが記載されているので、それに"/callback"をつけたものがWebhookURLです。


Deploy

Deployタグの下部にある"Manual deploy"をクリックしてデプロイします。


データを入れる

Postgresを使っているので必要に応じてデータを入れてください。

Rails consoleが使えるのでHerokuのドキュメントを参考にしてください。

https://devcenter.heroku.com/articles/getting-started-with-rails5#run-the-rails-console


Webhookの設定

HerokuのSettingsタブで確認したWebhookURLをLINEDevelopersのWebhook URLに設定します。

スクリーンショット 2019-08-01 15.17.05.png

個別で利用するだけならこれだけでOKですが、もしLINEグループにこのチャンネルを友達追加したい場合はすぐ下にある"Botのグループトーク参加"を利用するにする必要があります。


最後に

ここまできたらあとはLine上で話しかけるだけです。Let's talking!!

実際に作成した時とこの記事を書くまでに時差があり、手順が間違っていたり抜けていたりするかもしれないのでおかしな点があればご指摘いただけるとありがたいです。

herokuのログはheroku logsで確認できるのでrailsがうまく動かない場合は参照してみてください。

https://devcenter.heroku.com/articles/getting-started-with-rails5#view-logs