Raspberry Piとミニディスプレイ,各種センサを使ってダッシュボードを作ります.
今回のゴール
体調を崩して少し間が空いてしまいました.デザインが出来たところで天気予報を表示させていきます.
livedoorが,Weather Hacksと題して天気予報などのデータを提供しています.商用利用はできませんが,事例のところで九州の方言が楽しめるばい(方言).
ここでは,そのうちのお天気Webサービスを使います.レスポンスがJSON形式で返却されるため,取り扱いが非常に簡単です.
URLやパラメタの確認
URLやパラメタの地域(city)IDについては,お天気Webサービスのページに記述がありますのでよく読みましょう.例えば東京のidは130010です.
http://weather.livedoor.com/forecast/webservice/json/v1?city=130010
PCのブラウザで開くと,JSONと呼ばれる形式でデータが確認できます.
※スマートフォンのブラウザ等ではJSONハイジャック防止のため表示できない場合があります.
irb(Interactive Ruby)でデータを解析
では,ダッシュボードへ表示する準備です.
いきなりダッシュボードに載せる前に,rubyを対話型実行できるirb
を使って,データを解析してみましょう.
$ irb
irb(main):001:0>
irb
を起動すると,入力待ちの状態になります.1行ごとに入力した内容が実行され,結果が分かるという優れものです(exitで終了します).
irb(main):001:0> require 'uri'
=> true
require 'uri'
と入力して実行すると,true
という結果が返却されました.
このままじゃんじゃん入力します.
irb(main):002:0> require 'net/http'
=> true
irb(main):003:0> require 'yaml'
=> true
irb(main):004:0> data = Net::HTTP.get(URI.parse("http://weather.livedoor.com/forecast/webservice/json/v1?city=130010"))
=> "{\"pinpointLocations\":[{\"link\":\"http://weather.livedoor.com/area/forecast/1310100\",\"name\":\"\\u5343\\u4ee3\\u7530\\u533a\"},
(省略)
irb(main):005:0> json = YAML.load(data)
=> {"pinpointLocations"=>[{"link"=>"http://weather.livedoor.com/area/forecast/1310100", "name"=>"千代田区"},
(省略)
お天気WebサービスのJSONを解釈するところまで進めました.なんだか読めるモノが出てきたと思います.
引き続きお天気Webサービスの仕様を見ていると,forecasts
というプロパティに天気予報が入っていることが分かります.ちょっと見てみます.
irb(main):006:0> json["forecasts"]
=> [{"dateLabel"=>"今日", "telop"=>"曇時々晴", "date"=>"2017-10-31", "temperature"=>{"min"=>nil, "max"=>nil}, "image"=>{"width"=>50, "url"=>"http://weather.livedoor.com/img/icon/9.gif", "title"=>"曇時々晴", "height"=>31}},
(省略)
おっ,天気予報です.date
が日付,telop
が予報,temperature
が予想気温(夜に取得したのでその日の予想情報は無い)のようです.
だいたい取得方法がわかったので,ダッシュボードに載せていきましょう.
いざダッシュボードへ
ダッシュボードアプリの views/index.erb
を編集します.前回のデザインでカードを4個置いたので,そのうち1個を使いましょう.
<div class="card">
<h4 class="card-header">天気予報</h4>
<div class="card-body">
<%
# 天気予報取得処理
require 'uri'
require 'net/http'
require 'yaml'
data = Net::HTTP.get(URI.parse("http://weather.livedoor.com/forecast/webservice/json/v1?city=130010"))
json = YAML.load(data)
# 今日と明日の天気
today = json["forecasts"][0]["telop"]
tomorrow = json["forecasts"][1]["telop"]
%>
<p class="card-text">
<strong>今日</strong>: <%= today %><br>
<strong>明日</strong>: <%= tomorrow %>
</p>
</div>
</div>
補足 erb(embedded Ruby)テンプレートでは,<% ~ %>
の間にRubyスクリプトを記述したり,<%= ~ %>
の間にページに出力したい変数や式を記述することで,出力内容を柔軟に変えることができます.それ以外の部分は,そのまま出力されます.
すかさず http://localhost:4567/ にアクセスします.天気予報が表示されました.
もうちょっと,ダッシュボードへ
物足りないのでちょっと表示を良くしましょう.スクリプトの細かい説明は省きます.
<div class="card">
<h4 class="card-header">天気予報</h4>
<div class="card-body">
<%
# 天気予報取得処理
require 'uri'
require 'net/http'
require 'yaml'
data = Net::HTTP.get(URI.parse("http://weather.livedoor.com/forecast/webservice/json/v1?city=130010"))
json = YAML.load(data)
# 今日と明日の天気
today = json["forecasts"][0]["telop"]
tomorrow = json["forecasts"][1]["telop"]
%>
<p class="card-text">
<% json["forecasts"].each { |forecast| %>
<strong><%= forecast["dateLabel"] %></strong>:
<%= forecast["telop"] %>
<% if forecast["temperature"]["min"] %>
<span class="text-info">最低<%= forecast["temperature"]["min"]["celsius"] %>℃</span>
<% end %>
<% if forecast["temperature"]["max"] %>
<span class="text-danger">最高<%= forecast["temperature"]["max"]["celsius"] %>℃</span>
<% end %>
<br>
<% } %>
</p>
</div>
</div>
気温も表示されるようになったと思います.
ページを表示するたびにお天気Webサービスへアクセスするので,更新しすぎに注意しましょう.
今回はここまで.