Weather API を使って天気データを取得


お疲れ様です。
システム開発室、松山です。

今回は “天気API” を使って天気確認アプリを作ってみようと思います。
以前は気象庁から天気情報を購入する必要があったと思っていたのですが、
現在は無料で使用できる API もあるようなのでこちらを使用します。

ちなみに、気象庁でも気象データを無料で配布しているようですが、
基本的に気象データ(雨、風、気温など)なので、天気データとは異なるようです。
(過去の天気は配布していました)

要件

① Rakuten Rapid API の Open Weather Map を使用する
② HTTP 通信は以前作成したものをベースに流用
③ GPS の位置情報から、近くの都市の天気データを取得
④ 画面に緯度・経度・都市名・天気アイコンを表示
※ Unity 2019.4.11f1 で作成

Rakuten Rapid API

Rakuten Rapid API は、様々な機能の API を使用/開発することができるサービスです。
アカウント登録が必要ですが、無料で使用できる機能も多くあるので、色々試すことができそうです。
Rakuten Rapid API

Open Weather Map

Rakuten Rapid API にある、Open Weather Map を使用して天気データを取得します。
Open Weather Map

いくつか API がありますが、現在の天気を取得するなら、Current Weather Data API でいけそうです。

ブラウザ上でテストできるので、パラメータ調整しながら試してみると良いでしょう。
テストでも呼び出し回数にはカウントされるので注意。(月500回は無料)

API のリクエスト情報として、以下の情報が必要そうです。
・リクエストヘッダ(固定)

request.AddHeader("x-rapidapi-host", "community-open-weather-map.p.rapidapi.com");  // ホストアドレス
request.AddHeader("x-rapidapi-key", "xxxxxxxxxxxxxxxxx");  // アカウント毎に発行される API キー

・リクエストパラメータ
q : 都市ID(※必須)
他のオプションパラメータはなくても問題なさそうです。

都市ID については こちら から取得できます。
登録されている都市の天気データが取得できます。

HTTP 通信

上記要件に合わせて、過去に作成した処理をベースに実装を進めます。
過去記事はこちら

Scripts/Utility、Scripts/Api からソースをコピーしておきます
・ApiBase.cs
・CoroutineHandler.cs
・SigletonMonoBehaviour.cs
・Network.cs
・ApiSample.cs
大体、この辺り

OpenWeatherMap に対応するために機能を追加 / 調整します。

1. GET Method に対応する

GET Method に対応するため、JSON で渡されたリクエストパラメータを url に繋げる形で文字列化します。
かなり暫定的ですが、以下のような形で実装。

private string convGetParam(string json)
{
    string jsonTrim = json.Trim('{', '}');
    jsonTrim = jsonTrim.Replace("\"", "");
    string[] jsonArry = jsonTrim.Split(',');
    string retStr = "?";
    bool isFirst = true;
    foreach (var data in jsonArry)
    {
        if (!data.Contains(":")) break;
        if (!isFirst)
        {
            retStr += "&";
        }
        else
        {
            isFirst = false;
        }
        string[] paramAry = data.Split(':');
        retStr += paramAry[0] + "=" + paramAry[1];
    }
    return retStr;
}

2. リクエストヘッダを設定する

こちらは上記した通り、ホストアドレスと、API キーを設定します。
※ 値は OpenWeatherMap の画面に表示されています

3. HTTP リクエスト、レスポンスのパラメータを定義

Script / Api 下に、天気データ取得用のクラスを作成します。
今回は WeatherApi.cs で作成。

■ リクエスト
リクエストは都市名のみです。

[Serializable]
public struct Request
{
    public string q;
}

■ レスポンス
レスポンスはちょっと長いですが、こんな形に展開されます。
実は Weather 構造体だけあれば事足りますが、一応ひと通り取れるようにしました。

[Serializable]
public struct Coord
{
    public float lon;
    public float lat;
}
[Serializable]
public struct Weather
{
    public int    id;
    public string main;
    public string description;
    public string icon;
}
[Serializable]
public struct Main
{
    public float temp;
    public float fells_like;
    public float temp_min;
    public float temp_max;
    public int   pressure;
    public int   humidity;
}
[Serializable]
public struct Wind
{
    public float speed;
    public int   deg;
}
[Serializable]
public struct Rain
{
    // public float 1h;     // 1h を要素名にできない
}
[Serializable]
public struct Clouds
{
    public int all;
}
[Serializable]
public struct Sys
{
    public int    type;
    public int    id;
    public string country;
    public int    sunrise;
    public int    sunset;
}
[Serializable]
public struct Response
{
    public Coord         coord;
    public List<Weather> weather;
    // public string  base;     // base を要素名にできない
    public Main          main;
    public int           visibility;
    public Wind          wind;
    public Rain          rain;
    public Clouds        clouds;
    public int           dt;
    public Sys           sys;
    public int           timezone;
    public int           id;
    public string        name;
    public int           cod;
}

※ 一部使用できない名称がありコメントアウトしていますが、今回は使用しない情報のため気にしないことにします ^^;

一旦、通信関連はこんな感じで準備 OK かと。

GPS の使用

GPS についても、過去に作成したものを参考に必要なコードを記述します。
過去記事はこちら

今回の必要な GPS の処理としては、

Input.location.Start();
Input.compass.enabled = true;

最初にこれを行い、

Input.location.lastData.longitude;  // 経度
Input.location.lastData.latitude;   // 緯度

lastData で緯度経度を取得するだけになります。
※ 厳密には GPS を使用できるかの判定も行います。

Input.location.isEnabledByUser;     // GPS の使用が許可されているか
Input.location.status;              // Running 状態であれば使用可能

あと、ProjectSettings の Location Usage Description への記入を忘れないように注意してください。

天気データ

上述した通り、天気データを取得するには登録されている都市を指定する必要があるので、
検証用に47都道府県から1つの都市データを抽出して、
GPS で取得した緯度経度から、最も近い都市の天気データを取得する流れで実装します。

まずは都市データを作成します。
都市データとして、県名・市名・都市名(API用)・緯度・経度を、以下の構造体に定義。

private struct Data
{
    public string prefecture;   // 県名
    public string city;         // 市名
    public string name;         // API に渡す都市名
    public double lon;          // 経度
    public double lat;          // 緯度
}

こんな形にデータ化します。

static private List<Data> datas = new List<Data>
{
    new Data { prefecture = "北海道", city = "札幌市", name = "sapporo", lon = 141.346939, lat = 43.064171 },
    new Data { prefecture = "青森県", city = "青森市", name = "aomori", lon = 140.740005, lat = 40.82444 },
    new Data { prefecture = "岩手県", city = "盛岡市", name = "morioka", lon = 141.152496, lat = 39.703609 },
    new Data { prefecture = "宮城県", city = "仙台市", name = "sendai", lon = 140.871933, lat = 38.26889 },
    new Data { prefecture = "秋田県", city = "秋田市", name = "akita", lon = 140.116669, lat = 39.716671 },
    new Data { prefecture = "山形県", city = "山形市", name = "yamagata", lon = 139.821671, lat = 38.721668 },
    new Data { prefecture = "福島県", city = "福島市", name = "fukushima", lon = 140.383331, lat = 37.400002 },
    //
    // 中略
    //
    new Data { prefecture = "鹿児島県", city = "鹿児島市", name = "kagoshima", lon = 130.558136, lat = 31.560181 },
    new Data { prefecture = "沖縄県", city = "那覇市", name = "naha", lon = 127.681107, lat = 26.2125 }
};

あとは、現在の位置(緯度経度)から、最も近い都市データを検索します。
こんな関数があれば良いでしょうか。

static public Info NearbyCity(double lon, double lat)
{
    Info info = new Info();
    float dist = 9999f;
    foreach(Data dat in datas)
    {
        double z = (dat.lat - lat) * Lat2Km;    // -z が南
        double x = (dat.lon - lon) * Lat2Km;    // +x が東
        Vector3 v = new Vector3((float)x, 0, (float)z);
        if(v.magnitude < dist)
        {
            dist = v.magnitude;
            info.city = dat.prefecture + dat.city;
            info.name = dat.name;

        }
    }
    return info;
}

戻り値の構造体は表示用の県市名と、API 用の都市名になります。

public struct Info
{
    public string city;
    public string name;
}

画面に緯度・経度・都市名・天気アイコンを表示

Unity で画面を構成します。
ざっくりこんなイメージ

あとは GPS と API で取得した情報を表示してあげれば OK ということで、出来上がりはこちら。

天気ID などの情報や、天気アイコンはこちらで確認できます。
天気データ詳細

まとめ

駆け足になりましたが、ざっくり天気を表示するサンプルになったかなと思います。
天気データの取得自体は API 1つで実装できますが、登録されている都市と現在位置の紐付け(データ化)が若干手間なところでしょうか。
今回もサンプルプロジェクトを GitHub に上げておきます。
何かの参考にでもなれば幸いです。
Unity サンプル

Rakuten Rapid Api は他にも機能があるので、またの機会に使ってみたいと思います。
それでは、今回のお話はこれまでになります。


この記事をかいた人

About the author

松山賢勝

2019年8月から横浜オフィスに勤務。
経歴としてはクライアント開発が多いため、クライアント寄りの記事が多いかも。
趣味は自転車(ロード)と競馬。