Slack の ボット で 今日の天気を通知する - 降水予報 実装編

毎朝の天気が Slack に 通知されるようになりました. これは現在の天気を通知しているので、朝の天気を知ることはできても、その後どうなるかはわかりません. 今回は、その後 雨(雪) が 降るのかの予報も合わせて通知するようにしたいと思います.

作業環境

  • Slack
  • Node.js 6.9.1 LTS
  • Botkit 0.4.9
  • node-cron 1.2.1
  • moment-timezone 0.5.10

通知方法の検討

OpenWeatherMap で 取得できる予報は、「3時間ごと 5日間」と「日次で 16日間」の 2つがあります. 無料で使えるのは「3時間ごと 5日間」なので、こちらを使って降水予報を実装したいと思います.

取得できるデータには降水確率などの情報は無いですが、ダイレクトに天気状況と降水量があります. この降水量を使うことにして 24時間以内に降水量がある場合に、降水予報として通知するようにします.

Slack ボット の 実装

以下に 前回実装onTick: 部分を抜粋し今回の追加分をあげます.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
onTick: () => {
http.get(`http://api.openweathermap.org/data/2.5/weather?id=${city}&units=metric&appid=${apikey}`, (response) => {
let body = '';
response.setEncoding('utf8').on('data', (chunk) => { body += chunk; });
response.on('end', () => {
let current = JSON.parse(body);
let text =
`${moment.unix(current.dt).format('H:mm')} 現在 ${current.name} の 天気` +
`<http://openweathermap.org/img/w/${current.weather[0].icon.replace('n', 'd')}.png?${moment().unix()}| > ` +
`${current.weather[0].main}(${current.weather[0].description}) / ` +
`気温 ${Math.round(current.main.temp)} ℃ ` +
`${current.rain && current.rain['3h'] ? '/ 降雨量 ' + Math.ceil(current.rain['3h'] * 10) / 10 + ' mm ' : '' }` +
`${current.snow && current.snow['3h'] ? '/ 降雪量 ' + Math.ceil(current.snow['3h'] * 10) / 10 + ' mm ' : '' }`;

// ここから追加
http.get(`http://api.openweathermap.org/data/2.5/forecast?id=${city}&appid=${apikey}&units=metric&cnt=8`, (response) => {
body = '';
response.setEncoding('utf8').on('data', (chunk) => { body += chunk; });
response.on('end', () => {
let json = JSON.parse(body);
for (let i in json.list) {
let forecast = json.list[i];
if ((forecast.rain && forecast.rain['3h']) || (forecast.snow && forecast.snow['3h'])) {
text +=
`\n→ 降水予報 ${moment.utc(forecast.dt_txt).fromNow()} ` +
`(${moment.utc(forecast.dt_txt).utcOffset(9).format('M/D H:mm')}) / ${current.weather[0].main} ` +
`${forecast.rain && forecast.rain['3h'] ? '/ 降雨量 ' + Math.ceil(forecast.rain['3h'] * 10) / 10 + ' mm ' : '' }` +
`${forecast.snow && forecast.snow['3h'] ? '/ 降雪量 ' + Math.ceil(forecast.snow['3h'] * 10) / 10 + ' mm ' : '' }`;
break;
}
}
bot.say({ text: text, channel: channel });
});
});
// ここまで
});
});
},

予報は json.list に 入っているので for 文で 1つずつ処理します. 予報の時刻 forecast.dt_txt を 表示用にフォーマットし、後は現在の天気で処理したのとほぼ同じになります. アイコンが並ぶとわかりにくいので、予報のアイコンは不要としました.

ボットが発言する bot.say() は、予報の JSON を 取得した後になります.

通知!


朝の天気に加え 20時間後、明日 の 午前 3:00 に 雨が降るとの予報も表示されました. この予報だと傘の出番はなさそうですね.



予報も出せるようになったので、朝から傘が必要か、帰りには必要になるのかが分かるようになりました. 降水確率 ○○% というよりも、何時に、どのくらいの雨(雪) が 降るのかがはっきりするのでよいさそうです.

ちょっと気になるのが、天気の精度やデータの有無…
データやキャプチャは東京で統一するようにしたいと思っているのですが、天気の事なので思うような状態でないことはあります. その際に他の都市をいろいろと探すのですが、どうも他の天気予報と合ってなかったり、極端な話 OpenWeatherMap の 地図 とも合ってない時があるような気も…
また、天気 が Rain に なっているのに、現在の天気 API に rain.3h が 入ってなかったりと、なのに Clear で 0.1 mm とか… 不思議だ…
無料で使わせてもらっているので、多くは望まないのですが、精度が悪いようだと困るなぁ. 今度、いろいろと比較を出して調べてみよう.