【Node.js, heroku】Twitter botで天気予報(画像付き)

## 1.作ったもの
朝7時にツイートを実行します。
①現在の全国の天気を画像でツイート
②現在の全国の天気と気温をテキストでツイート
③9時～24時までの3時間ごとの全国の天気と気温をテキストでツイート
④9時～24時までの3時間ごとの全国の天気を画像でツイート

### (1)ツイート内容(2022/1/3のツイート)
//ツイート全体
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228630/24125400-3af0-fa1a-c7a3-688edb24f031.png)

//画像抜粋(現在の天気)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228630/56ff240f-ff5d-66e0-a182-168068337907.png)

//画像抜粋(3時間ごとの天気)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228630/35ed3364-d88f-8727-2554-ea0d4da9bdb2.png)

### (2)bot本体の仕様
以前作成した下記の星座占いbotに機能追加する形で実装しています。
[参考]【Node.js＋heroku】Twitter星座占いbot作成

https://qiita.com/natsume_410/items/895d6a908da98005e1a0

### (3)設計書・プログラム
最新の設計書・プログラム等は下記のGoogleDriveに格納しています。
(過去の画像データ等が残ってしまっているため、GitHubは非公開設定です)

https://drive.google.com/drive/folders/1W8bNSsk9IMrxx1gzwPH7_aAfSw5K-I8w

### (4)天気情報の取得元
画像にもありますが、OpenWeatherMapからデータを取得しています。

https://openweathermap.org/api

## 2.設計
詳しくは設計書参照なのですが、簡単に説明すると以下の流れで処理しています。
(1)現在の全国の天気
①GoogleDriveから背景画像のデータを取得する
②OpenWeatherMapから各都市の現在の気象情報を取得する(weather指定)
③OpenWeatherMapから天候アイコン画像のデータを取得する
④天候アイコン画像のデータを背景画像に描画する
⑤編集した背景画像をツイート
⑥現在の気象情報テキストをツイート

(2)3時間ごとの全国の天気
①GoogleDriveから背景画像のデータを取得する
②OpenWeatherMapから各都市の3時間ごとの気象情報を取得する(forecast指定)
③3時間ごとの気象情報テキストをツイート
④OpenWeatherMapから天候アイコン画像のデータを取得する
⑤天候アイコン画像のデータを背景画像に描画する
⑥編集した背景画像をツイート

## 3.実装
### (1)OpenWeatherMapのAPI呼出し
詳しくはプログラム参照なのですが、APIを呼び出す関数は本体から以下のソースに切り出しています。
request-promiseを使えば関数1つずつで済むのではないか、ということに後から気付きましたが、今後機会があれば修正したいと思います…

```js:owmFunc.js
"use strict";
//----------external function declaration----------
const subs = require('./subFunc');

//----------const declaration----------
const request = require('request');

//----------OpenWeatherMap functions----------
function forecast(city, api_key) {
    return new Promise(function(resolve, reject) {
        callForecast(city, api_key, function (error, data) {
            if (!error) {
                resolve(data);
            } else {
                let error_msg = "OWM API(forecast) call error(" + city + ")." + subs.editErrMsg(error);
                reject(error_msg);
            }
        });
    });
}

function callForecast(city, api_key, callback) {
    var url = 'http://api.openweathermap.org/data/2.5/forecast?q=' + city + ',jp&units=metric&cnt=6&lang=ja&appid=' + api_key;
    request({ url: url, json: true }, function (error, response) {
        if (!error) { 
            callback(null, response.body);
        } else {
            callback(subs.editErrMsg(error));
        }
    })
}

function weather(city, api_key) {
    return new Promise(function(resolve, reject) {
        callWeather(city, api_key, function (error, data) {
            if (!error) {
                resolve(data);
            } else {
                let error_msg = "OWM API(weather) call error(" + city + ")." + subs.editErrMsg(error);
                reject(error_msg);
            }
        });
    });
}

function callWeather(city, api_key, callback) {
    var url = 'http://api.openweathermap.org/data/2.5/weather?q=' + city + ',jp&units=metric&lang=ja&appid=' + api_key;
    request({ url: url, json: true }, function (error, response) {
        if (!error) { 
            callback(null, response.body);
        } else {
            callback(subs.editErrMsg(error));
        }
    })
}
```

### (2)天候アイコンの読込
天候アイコンの読込は以下のように行っています。
node-canvasのloadImageメソッドに天候アイコンのURLを渡す形で画像データを取得しています。

```js:subFunc.js
"use strict";
//----------external function declaration----------
const canvas = require('canvas');

//～省略～

function loadCanvasImage(load_data) {
    return new Promise(async function(resolve, reject) {
        try {
            let res = await canvas.loadImage(load_data);
            resolve(res);
        } catch (error) {
            reject("Data load error." + "Data:(" + load_data + ")" + editErrMsg(error));
        }
    });
}
```

### (3)APIキーの設定
APIキーはherokuのコンフィグ管理画面から追加しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228630/8828b44d-8fea-66be-3c45-40c3563d09de.png)



## 4.参考サイト
### (1)OpenWeatherMap関連
[参考]Weather API - OpenWeatherMap

https://openweathermap.org/api

[参考]無料天気予報APIのOpenWeatherMapを使ってみる

https://qiita.com/nownabe/items/aeac1ce0977be963a740


[参考]Node.jsでお天気を取得してみよう

https://qiita.com/RoaaaA/items/70b1beb262691f4c0718

[参考]無料天気予報API【OpenWeatherMap】を使って天気予報サイトデモを作ってみた ~APIの呼び出し編~

https://hibi-update.org/other/openweathermap-api/


### (2)URLから画像の読込
[参考]node-canvas

https://github.com/Automattic/node-canvas#loadimage

### (3)Googleドライブから画像データを取得
[参考]【Node.js, heroku】Googleドライブの操作(データ取得/更新)

https://qiita.com/natsume_410/items/da7ffb91fc5181853225