その他メモ

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

無料天気予報API【OpenWeatherMap】を使ってiPhoneのアプリ風の天気予報デモを作成してみました。

作成の流れを「APIの呼び出し編」「天気背景アニメーション作成編」に分けて記事にしていきたいと思います。
今回は、【OpenWeatherMap】APIの呼び出し編です。

作成したDEMOは以下で確認できます。

【OpenWeatherMap】とは

【OpenWeatherMap】は無料で利用できる天気予報APIです。(有料プランあり)

https://openweathermap.org/

無料で利用できるAPIの項目は以下の通り(1分間に60コール/1ヶ月に1,000,000コールまで)

  • 現在の天気
  • 3時間ごと5日間の天気予報
  • 天気図1.0
  • 天気予報
  • UV指数
  • 気象ステーション

今回はその中でも、以下のAPIを使用してデモを作成していきます。

  • 現在の天気
  • 3時間ごと5日間の天気予報

【OpenWeatherMap】APIの使い方

APIキーを取得する

【OpenWeatherMap】の使い方は難しくありません。
まずは使用するためのAPIキーを取得しちゃいましょう。
下記のURLにアクセスして、アカウントを作成します。

https://home.openweathermap.org/users/sign_up

アカウントが作成できたら「API keys」に移動して「key」をコピーすればOKです。

【OpenWeatherMap】のデータを確認してみる

API keyの取得が出来たので早速【OpenWeatherMap】を使っていきます。どのような情報が取得できるのかを確認するために便利な、Chrome拡張アプリの「Advanced REST Client」を使用してみます。

試しに東京の現在の天気を取得してみます。
以下のページにアクセスします。

https://openweathermap.org/current

現在の天気を取得するためのAPI呼び出しURLが確認できます。これを先ほどの「Advanced REST Client」に入力していきます。

HostにURLを入力した後、右のタブをクリックすると、Pathとパラメータ を入力する項目が出てきます。

現在の天気を取得したいので
Pathを「/data/2.5/weather」
パラメータに取得したい場所(東京)と温度を摂氏で表示するための「units=metric」と先ほど取得したAPI keyを入力します。

入力できたら「SEND」を押します。

以下のようにデータが表示出来ていればOKです。
※API keyを取得したばかりだと反映まで若干のタイムラグがあるので表示されない場合があります。

現在の天気APIで取得できるデータ

現在の天気用APIで取得できる情報を確認していきます。
以下取得したJSONのサンプルです。

{
    "coord": {
        "lon": 139.69,
        "lat": 35.69
    },
    "weather": [{
        "id": 802,
        "main": "Clouds",
        "description": "scattered clouds",
        "icon": "03d"
    }],
    "base": "stations",
    "main": {
        "temp": 29.64,
        "feels_like": 30.54,
        "temp_min": 28,
        "temp_max": 31.67,
        "pressure": 999,
        "humidity": 65
    },
    "visibility": 10000,
    "wind": {
        "speed": 5.7,
        "deg": 180
    },
    "clouds": {
        "all": 40
    },
    "dt": 1592286962,
    "sys": {
        "type": 1,
        "id": 8077,
        "country": "JP",
        "sunrise": 1592249100,
        "sunset": 1592301536
    },
    "timezone": 32400,
    "id": 1850144,
    "name": "Tokyo",
    "cod": 200
}

現在の天気APIで取得できる情報が以下になります。
この取得できる情報を利用して天気予報のデモを作成していきます。

概要
coordlon都市の地理的位置、経度
lat都市の地理的位置、緯度
weatherid気象条件ID
main気象パラメータのグループ(雨、雪、極端など)
description気象情報詳細
icon天気アイコンID
base内部パラメータ
maintemp温度
feels_like体感温度
pressure大気圧(sea_levelまたはgrnd_levelデータがない場合は海面に)、hPa
humidity湿度、%
temp_min現在の最低気温
temp_max現在の最高気温
sea_level海面の気圧、hPa
grnd_level地上レベルの大気圧、hPa
windspeed風速。
単位のデフォルト:メートル/秒、メートル法:メートル/秒、インペリアル:マイル/時。
deg風向、度(気象)
gust突風。
単位のデフォルト:メートル/秒、メートル法:メートル/秒、インペリアル:マイル/時
cloudsall曇り、%
rain1h過去1時間の雨量、mm
3h過去3時間の雨量、mm
snow1h過去1時間の積雪量、mm
3h過去3時間の積雪量、mm
dtデータ計算の時間、UNIX、UTC
systype内部パラメータ
id内部パラメータ
message内部パラメータ
country国コード(GB、JPなど)
sunrise日の出時刻、UNIX、UTC
sunset日没時間、UNIX、UTC
timezoneUTCから秒単位でシフト
id都市ID
name都市の名前
cod内部パラメータ

3時間ごと5日間の天気予報

続いて3時間ごと5日間の天気予報APIのデータを確認していきます。
以下のページから現在の天気同様にURLが確認できます。

https://openweathermap.org/forecast5

以下のようなJSONで取得できます。

{
    "cod": "200",
    "message": 0,
    "cnt": 40,
    "list": [{
            "dt": 1592298000,
            "main": {
                "temp": 28.35,
                "feels_like": 26.78,
                "temp_min": 27.17,
                "temp_max": 28.35,
                "pressure": 1000,
                "sea_level": 1001,
                "grnd_level": 997,
                "humidity": 56,
                "temp_kf": 1.18
            },
            "weather": [{
                "id": 802,
                "main": "Clouds",
                "description": "scattered clouds",
                "icon": "03d"
            }],
            "clouds": {
                "all": 36
            },
            "wind": {
                "speed": 6.68,
                "deg": 178
            },
            "sys": {
                "pod": "d"
            },
            "dt_txt": "2020-06-16 09:00:00"
        },
        {
            "dt": 1592308800,
            "main": {
                "temp": 26.21,
                "feels_like": 24.81,
                "temp_min": 25.31,
                "temp_max": 26.21,
                "pressure": 1002,
                "sea_level": 1003,
                "grnd_level": 998,
                "humidity": 57,
                "temp_kf": 0.9
            },
            "weather": [{
                "id": 500,
                "main": "Rain",
                "description": "light rain",
                "icon": "10n"
            }],
            "clouds": {
                "all": 37
            },
            "wind": {
                "speed": 5.4,
                "deg": 41
            },
            "rain": {
                "3h": 0.25
            },
            "sys": {
                "pod": "n"
            },
            "dt_txt": "2020-06-16 12:00:00"
        }
    //省略
    ]
}

データに一覧は以下に。現在の天気のデータアクセスと一部違う箇所があるので注意が必要です。

概要
code内部パラメータ
message内部パラメータ
cityid都市ID
name都市の名前
coordlat都市の地理的位置、緯度
lon都市の地理的位置、経度
country国コード(GB、JPなど)
timezoneUTCから秒単位でシフト
cntこのAPI呼び出しによって返された行数
listdt予測されるデータの時間、UNIX、UTC
maintemp温度
feels_like体感温度
temp_min現在の最低気温
temp_max現在の最高気温
pressureデフォルトでの海面の気圧、hPa
sea_level海面の気圧、hPa
grnd_level地上レベルの大気圧、hPa
humidity湿度、%
temp_kf内部パラメータ
weatherid気象条件ID
main気象パラメータのグループ(雨、雪、極端など)
description気象情報詳細
icon天気アイコンID
cloudsall曇り、%
windspeed風速。
単位のデフォルト:メートル/秒、メートル法:メートル/秒、インペリアル:マイル/時。
deg風向、度(気象)
rain3h過去3時間の雨量、mm
snow3h過去3時間の積雪量、mm
dt_txt予測されるデータの時間、ISO、UTC

jQuery ajaxでデータを取得する

引き続きJavaScript(jQuery)を使用してデータを取得して表示していきます。以下の関数でAPIから取得します。

JS

var API_KEY = '00000000000000000000';
var defaultCity = 'Tokyo';
//現在の天気を取得
function currentWeather() {
    $.ajax({
            url: '//api.openweathermap.org/data/2.5/weather?q=' + defaultCity + ',jp&units=metric&appid=' + API_KEY,
            dataType: 'json',
            type: 'GET'
        })
        .done(function (data) {
            //呼び出した時の処理
        })
        .fail(function (data) {
            console.log('現在の天気を取得出来ませんでした。')
        });
}

//3時間ごとの天気を取得
function threeWeather() {
    $.ajax({
            url: '//api.openweathermap.org/data/2.5/forecast?q=' + defaultCity + ',jp&units=metric&appid=' + API_KEY,
            dataType: 'json',
            type: 'GET'
        })
        .done(function (data) {
            //呼び出した時の処理
            })
        })
        .fail(function (data) {
            console.log('3時間ごとの天気を取得出来ませんでした。')
        });
}

これで引数「data」から情報にアクセスできるようになりました。
続いて必要なデータを格納してDOM要素に描写するようにします。

取得したデータを格納する

取得したデータから表示したい内容を変数に格納していきます。
天気予報の時間帯を表示するための関数も用意します。

JS

var city = {
    name: '',
    date: '',
    time: '',
    weather: '',
    description: '',
    temp: '',
    tempMin: '',
    tempMax: '',
    feelsLike: '',
    pressure: '',
    humidity: '',
    windSpeed: '',
    WindSpeedUnit: '',
    windDeg: '',
    cloudsAll: '',
    sunriseDate: '',
    sunriseTime: '',
    sunsetDate: '',
    sunsetTime: '',
};
var current = {
    day: '',
    month: '',
    date: '',
    hours: '',
    minitutes: '',
    time: '',
    timeText: '',
}

//データ格納
function getWeatherData(data) {
    (data.name) ? city.name = data.name.toUpperCase(): city.name;
    city.description = data.weather[0].description;
    city.date = new Date(data.dt * 1000);
    city.temp = Math.round(data.main.temp);
    city.tempMin = Math.round(data.main.temp_min);
    city.tempMax = Math.round(data.main.temp_max);
    city.feelsLike = Math.round(data.main.feels_like);
    city.pressure = Math.round(data.main.pressure);
    city.humidity = Math.round(data.main.humidity);
    city.windSpeed = Math.round(data.wind.speed);
    city.windDeg = Math.round(data.wind.deg);
    city.cloudsAll = Math.round(data.clouds.all);
    (data.sys.sunrise) ? city.sunriseDate = new Date(data.sys.sunrise * 1000): city.sunriseDate = undefined; //unixtime to date
    (data.sys.sunset) ? city.sunsetDate = new Date(data.sys.sunset * 1000): city.sunsetDate = undefined; //unixtime to date
    if (city.sunriseDate && city.sunsetDate) {
        city.sunriseTime = city.sunriseDate.getHours() + ':' + city.sunriseDate.getMinutes();
        city.sunsetTime = city.sunsetDate.getHours() + ':' + city.sunsetDate.getMinutes();
    } else {
        city.sunriseTime = '-';
        city.sunsetTime = '-';
    }
}

//日付&時間取得
function createDate(date) {
    current.day = date;
    current.month = current.day.getMonth() + 1;
    current.date = current.month + '/' + current.day.getDate();
    current.hours = current.day.getHours();
    current.minitutes = ('0' + current.day.getMinutes()).slice(-2);
    current.time = current.hours + ':' + current.minitutes;
    current.timeText = current.date + ' ' + current.time;
}

DOM要素に描写する

変数に格納したデータをDOM要素に描写していきます。
ベースとなるHTMLを作成します。

現在の天気をベースに描写して、「weather-report」に3時間ごとの天気予報を描写させるようにします。

HTML

<div class="city-wrap">
    <h2 id="city-name" class="city-name"></h2>
    <div id="weather-discription" class="weather-discription"></div>
    <div id="weather-temp" class="weather-temp big"></div>
    <div id="weather-date" class="weather-date"></div>
    <div class="detail-list">
        <div class="detail-item">
            <div class="text">最高気温</div>
            <div id="tempMax" class="value tempMin"></div>
        </div>
        <div class="detail-item">
            <div class="text">最低気温</div>
            <div id="tempMin" class="value tempMax"></div>
        </div>
        <div class="detail-item">
            <div class="text">体感気温</div>
            <div id="feelsLike" class="value feelsLike"></div>
        </div>
        <div class="detail-item">
            <div class="text">湿度</div>
            <div id="humidity" class="value humidity"></div>
        </div>
        <div class="detail-item">
            <div class="text">日の出</div>
            <div id="sunrise" class="value sunrise"></div>
        </div>
        <div class="detail-item">
            <div class="text">日の入</div>
            <div id="sunset" class="value sunset"></div>
        </div>
        <div class="detail-item">
            <div class="text">風速</div>
            <div id="windSpeedUnit" class="value windSpeedUnit"></div>
        </div>
        <div class="detail-item">
            <div class="text">気圧</div>
            <div id="pressure" class="value pressure"></div>
        </div>
    </div>
    <div class="weather-reportWrap">
        <div id="weather-report" class="weather-report"></div>
    </div>
</div>

描写用の単位を変数で用意します。3時間ごとの天気予報は曜日も描写するようにします。

JS

var UNIT = {
    TEMP: '°',
    PRESSURE: 'hPa',
    HUMIDITY: '%',
    WINDSPEED: 'm/s',
    MIDDLE_DOT: ':'
}
//DOM要素に描写
function domWeatherWrite() {
    $('#city-name').html(city.name);
    $('#weather-temp').html(city.temp + UNIT.TEMP);
    $('#tempMin').html(city.tempMin + UNIT.TEMP);
    $('#tempMax').html(city.tempMax + UNIT.TEMP);
    $('#feelsLike').html(city.feelsLike + UNIT.TEMP);
    $('#humidity').html(city.humidity + UNIT.HUMIDITY);
    $('#sunrise').html(city.sunriseTime);
    $('#sunset').html(city.sunsetTime);
    $('#windSpeedUnit').html(city.windSpeed + UNIT.WINDSPEED);
    $('#pressure').html(city.pressure + UNIT.PRESSURE);
    $('#weather-date').html(current.timeText);
    $('.detail-list').css('display', 'flex');
}

//DOM要素に描写 3時間ごとver
function domThreeWeatherWrite(data, i) {
    var week = new Array("(日)", "(月)", "(火)", "(水)", "(木)", "(金)", "(土)");
    var dt = data.list[i].dt_txt;
    var date = new Date(dt.replace(/-/g, "/"));
    date.setHours(date.getHours() + 9);
    var month = date.getMonth() + 1;
    var day = month + "/" + date.getDate();
    var week = week[date.getDay()];
    var time = date.getHours() + ":00";
    var main = (data.list[i].weather[0].main).toLowerCase();
    var html =
        '<div class="weather-reportItem">' +
        '<div class="weather-day">' + day + '</div>' +
        '<div class="weather-week">' + week + '</div>' +
        '<div class="weather-time">' + time + '</div>' +
        '<div class="weather-main ' + main + '"></div>' +
        '<div class="weather-temp">' + Math.round(data.list[i].main.temp) + UNIT.TEMP + '</div>' +
        '</div>';
    return html
}

天気予報の詳細情報を日本語で表示させる

天気予報の詳細情報「discription」を分岐させて内容を日本語に変換しておきます。「discription」の種類は以下から確認できます。(サンプルコードでの日本語変換は全部対応は出来ていません。)

https://openweathermap.org/weather-conditions

//天気情報分岐
function getDiscription(disc) {
    switch (disc) {
        case 'clear sky':
            return $('#weather-discription').html('快晴');
            break;
        case 'few clouds':
            return $('#weather-discription').html('くもり(雲少なめ)');
            break;
        case 'scattered clouds':
            return $('#weather-discription').html('くもり(雲ふつう)');
            break;
        case 'broken clouds':
            return $('#weather-discription').html('くもり(雲多め)');
            break;
        case 'overcast clouds':
            return $('#weather-discription').html('くもり(雲多め)');
            break;
        case 'light intensity shower rain':
            return $('#weather-discription').html('小雨のにわか雨');
            break;
        case 'shower rain':
            return $('#weather-discription').html('にわか雨');
            break;
        case 'heavy intensity shower rain':
            return $('#weather-discription').html('大雨のにわか雨');
            break;
        case 'light rain':
            return $('#weather-discription').html('小雨');
            break;
        case 'moderate rain':
            return $('#weather-discription').html('雨');
            break;
        case 'heavy intensity rain':
            return $('#weather-discription').html('大雨');
            break;
        case 'very heavy rain':
            return $('#weather-discription').html('激しい大雨');
            break;
        case 'rain':
            return $('#weather-discription').html('雨');
            break;
        case 'thunderstorm':
            return $('#weather-discription').html('雷雨');
            break;
        case 'snow':
            return $('#weather-discription').html('雪');
            break;
        case 'mist':
            return $('#weather-discription').html('靄');
            break;
        case 'tornado':
            return $('#weather-discription').html('強風');
            break;
        default:
            return disc;
    }
}

用意した関数を発火させる

最後に用意した関数を起動させます。
現在の天気と3時間ごとの天気予報の読み込み完了後に発火させていきます。
3時間ごとの天気予報はclickイベントで詳細を現在の天気と入れ替えれる仕様にします。

//現在の天気を取得
function currentWeather() {
    $.ajax({
            url: '//api.openweathermap.org/data/2.5/weather?q=' + defaultCity + ',jp&units=metric&appid=' + API_KEY,
            dataType: 'json',
            type: 'GET'
        })
        .done(function (data) {
            getWeatherData(data);
            createDate(city.date);
            getDiscription(city.description);
            domWeatherWrite();
        })
        .fail(function (data) {
            console.log('現在の天気を取得出来ませんでした。')
        });
}

//3時間ごとの天気を取得
function threeWeather() {
    $.ajax({
            url: '//api.openweathermap.org/data/2.5/forecast?q=' + defaultCity + ',jp&units=metric&appid=' + API_KEY,
            dataType: 'json',
            type: 'GET'
        })
        .done(function (data) {
            var insertHTML = '';
            for (var i = 0; i <= 12; i++) {
                insertHTML += domThreeWeatherWrite(data, i);
            }
            $('#weather-report').html(insertHTML);

            $('.weather-reportItem').click(function () {
                var targetNum = $(this).index();
                getWeatherData(data.list[targetNum]);
                createDate(new Date(data.list[targetNum].dt * 1000));
                getDiscription(city.description);
                domWeatherWrite();
                $('body, html').animate({
                    scrollTop: 0
                }, 300, 'linear');
            })
        })
        .fail(function (data) {
            console.log('3時間ごとの天気を取得出来ませんでした。')
        });
}

function weatherInit() {
    currentWeather();
    threeWeather();
}
weatherInit();

これで以下のようにデータを描写することが出来ました。

最後に

今回は、無料天気予報API【OpenWeatherMap】を使ってiPhoneのアプリ風の天気予報デモを作成の「APIの呼び出し編」を紹介いたしました。

次回は、「天気背景アニメーション作成編」を紹介していきます。

参考サイト

https://openweathermap.org/
https://qiita.com/mikan3rd/items/a5bc87a2242e67cf17a4
https://tacs-port.tech/blog/api/blog-132/