通知センターで天気予報を通知するサンプル


例えば、ターミナルで`ruby weather.rb`を実行すると、こんな感じで表示してくれます。

![スクリーンショット 2014-07-09 20.59.53.png](https://qiita-image-store.s3.amazonaws.com/0/30707/61b78de7-033a-0667-8980-ef0df7b75ec9.png "スクリーンショット 2014-07-09 20.59.53.png")

# やっていること

- Livedoorが提供している[お天気Webサービス](http://weather.livedoor.com/weather_hacks/webservice)のAPIに[6桁からなるCity ID](http://weather.livedoor.com/forecast/rss/primary_area.xml)を渡し、
- 返ってきたJSONをパースし、
- その結果をTerminal-notifierに渡す

通知センターで何かしたい時に、Rubyで気軽にさくさくっと書けるあたりが面白いね。

# ソースコード

```ruby:weather.rb
#
# 天気予報をOSXの通知センターで表示するサンプルプログラム
#

require 'json'
require 'open-uri'
require 'terminal-notifier'

def notify_weather
    # location_idについては、以下を参照のこと
    # http://weather.livedoor.com/forecast/rss/primary_area.xml
    location_id = '012010'
    
    idx = 0
    json_url = "http://weather.livedoor.com/forecast/webservice/json/v1?city=#{location_id}"
    weather_url = "http://weather.livedoor.com/area/forecast/#{location_id}"

    begin
        received_body = open(json_url).read
        json = JSON.parse(received_body)
    rescue => e
        p e.message
        return false
    end

    json_title = json['title']
    json_expected_condition = json['forecasts'][idx]['telop']
    json_celsius_max = json['forecasts'][idx]['temperature']['max'] ? json['forecasts'][idx]['temperature']['max']['celsius'] : "不明"
    json_celsius_min = json['forecasts'][idx]['temperature']['min'] ? json['forecasts'][idx]['temperature']['min']['celsius'] : "不明"

    title_message = json_title
    body_message = "#{json_expected_condition} (#{json_celsius_max} / #{json_celsius_min})"

    TerminalNotifier.notify(body_message, {
            :title => title_message,
            :open  => weather_url
        }
    )
end

notify_weather
```

例えば、これを[launchd(8)の使い方](http://qiita.com/archinwater/items/4c2e9174e4898a197de6)を参考にしながら登録してやれば、1時間に1回とか天気が自動で通知されるっていう仕組みを作ることができる。

但し、あんまり実行しすぎないようにね。

# 追記(2014/7/10)

はてブにて、

>kjw_junichi
>これ、Mavericksだと、アイコン表示を天気の奴用意すれば、さらに面白そうだなぁ

こんな感じですよね。

![2NHHd1bWtE0N5Ij4xym3enHjnGCmXFQa9tpn_0XnyuY.png](https://qiita-image-store.s3.amazonaws.com/0/30707/11952889-6c54-1bac-c498-0ddf04a4d3cd.png)

- お天気Webサービスで取得できるJSONには、お天気アイコンのURLが埋め込まれていた
- terminal-notifier.notifyの実装では、TerminalNotifier.executeにまんまオプション引き渡しているっぽい

```ruby:terminal-notifier.rb
  def notify(message, options = {}, verbose = false)
    TerminalNotifier.execute(verbose, options.merge(:message => message))
    $?.success?
  end
```

- 実体のソースを見てみれば、それっぽい記述もあった

```objc:terminal-notifier/AppDelgate.m
    // Mavericks options
    if(options[@"appIcon"]){
      // replacement app icon
      [userNotification setValue:[self getImageFromURL:options[@"appIcon"]] forKey:@"_identityImage"];
      [userNotification setValue:@(true) forKey:@"_identityImageHasBorder"];
    }
```

こりゃ行けそうだと、早速実装してみました。(実行にはOSX Mavericks以上の環境が必要)

```ruby:weather_2.rb
#
# 天気予報をOSXの通知センターで表示するサンプルプログラム
# アイコンも表示できるぜ！版
#

require 'json'
require 'open-uri'
require 'terminal-notifier'

def notify_weather
    # location_idについては、以下を参照のこと
    # http://weather.livedoor.com/forecast/rss/primary_area.xml
    location_id = '012010'
    
    idx = 1  # 0: 今日の天気、1: 明日の天気、2: あさっての天気
    json_url = "http://weather.livedoor.com/forecast/webservice/json/v1?city=#{location_id}"
    weather_url = "http://weather.livedoor.com/area/forecast/#{location_id}"
    weather_icon_path = "/tmp/weather_icon.gif"

    begin
        received_body = open(json_url).read
        json = JSON.parse(received_body)
    rescue => e
        p e.message
        return false
    end

    json_title = json['title']
    json_expected_condition = json['forecasts'][idx]['telop']
    json_celsius_max = json['forecasts'][idx]['temperature']['max'] ? json['forecasts'][idx]['temperature']['max']['celsius'] : "不明"
    json_celsius_min = json['forecasts'][idx]['temperature']['min'] ? json['forecasts'][idx]['temperature']['min']['celsius'] : "不明"
    json_imageurl = json['forecasts'][idx]['image']['url']

    title_message = json_title
    body_message = "#{json_expected_condition} (#{json_celsius_max} / #{json_celsius_min})"

    # 天気画像のダウンロード
    begin
        open(weather_icon_path, 'wb') do |weather_icon|
            open(json_imageurl) do |data|
                weather_icon.write(data.read)
            end
        end
    rescue => e
        p e.message
        return false
    end

    TerminalNotifier.notify(body_message, {
            :title => title_message,
            :open  => weather_url,
            :appIcon => weather_icon_path,
        }
    )
end

notify_weather
```

コメントありがとうございました。おかげさまでまた一つ勉強になりました！