気象情報サイトのデータをNode-REDで使ってみよう!!

1. 概要

気象情報サイトには、気象庁のサイトと民営の天気予報会社のサイトの2種類があります。 また、データにアクセスする方法としては、HPにアクセスして視覚的に情報を取得する方法とAPIにアクセスすることで文字情報を取得する方法の2種類があります。両方のサービスを実施しているサイトもありますし、片方しかサービスしていないサイトもあります。

農業栽培や漁業養殖などでは、気温や照度や湿度などの予報も重要ですが、それらがどうだったのかという観測情報も必要です。なぜなら、農地や養殖地での温度や湿度などと気象サイトの観測実績から、予報サイトの値と実際の測定値との相関が分かれば、予報サイトの予報に対して農地や養殖地で同温度や湿度などがどのように振れるかという予測が立つようになるからです。

次の図は、過去一週間分の気象サイトの温度と部屋の温度の比較をしたものです。外気が上がっていくにつれて、部屋の温度も上がっていくのが分かります。このような傾向をうまく活用することで、効率の良い農業栽培や漁業養殖が出来ないかと考えます。

農地や養殖地などからの環境情報をクラウドに上げるのと同様に、気象サイトの観測情報もクラウドに保存し、それらの相関を確認するのが良いと考えられます。そして、このときの観測情報や予測情報は、文字情報のデータが扱いやすいです。図像では解析するのに大変になります。

本投稿では、民営の気象サイトからの情報をNode-REDを使って取得する方法と、取得したデータをグラフ化する方法を説明します。

注意点としては、基本気象庁のサイトは無料だが、民営のサイトは一般的に有料である。有料の民営サイトの方が細かい情報が揃っています。コストパフォーマンスを考えて気象庁のデータ、民営会社のデータ、実測データの関係を掴んでうまく使うのが良いと思われます。

まず、初めにNode-REDを使いAPIにアクセスすることで、気象サイトからデータの取得方法を説明したのちに、取得したデータをグラフ化することも説明します。

2.気象サイトのデータ取得

ここでは、Node-REDでAPIを使って、気象庁と民営会社Lifesocketのデータを取得してみます。

2.1. 気象庁のデータ取得

気象庁のAPIは以下の2つが公開されています。

  1. ① 地方気象台の発表する1日毎の天気予報データが取得できるAPI
  2. ② 地方気象台の発表する天気予報の概要が取得できるAPI

順番にNode-REDを使ってアクセスしてみます。

2.1.1. 通常の天気予報のAPI

通常の天気予報のAPIのアドレスは、

https://www.jma.go.jp/bosai/forecast/data/forecast/250000.json

です。250000の数字は、エリアのコードになっています。一覧の在処が不明なので変えてアクセスして探してみてください。ちなみに250000は滋賀県のエリアコードです。

以下に、Node-REDのフローエディタの図を載せます。

ノードは3つです。インジェクトノードとHTTP リクエストノードとデバッグノードです。このうち、インジェクトノードは取得するためのボタン替わりですので、配置するだけでOKです。同様にデバッグノードを取得したデータを表示するためだけなので、配置するだけでOKです。

HTTP リクエストノードの中に、APIアドレスを記載します。

  1. 1) メソッドはGETを選びます。
  2. 2) URLの部分にAPIアドレスをコピーします。

以上で、デプロイしたらインジェクトノードのボタンを押してください。上の右側のように、1日毎の3日間の天気予報がJSON形式で表示されます。滋賀県の場合は、北部と南部の2種類を取得できます。

2.1.2. 概要の天気予報のAPI

概要の天気予報のAPIは、以下です。

https://www.jma.go.jp/bosai/forecast/data/overview_forecast/250000.json

forecastの部分がoverview_forecastに変わっています。

こちらも同じようにNode-REDのフローエディタの画面を以下に示します。

こちらも同じように3つのノードを配置して、HTTPリクエストノードの中にAPIアドレスを記載します。

デプロイ後、インジェクトノードのボタンを押すと、上のように、言葉で天気予報が表示されます。わかりやすいですが、相関を取ったりするのには使えないです。

2.2. 気象サイト Lifesocketのデータ取得

民間の気象サイトとしてここでは、Lifesocketのデータを取得します。Lifesocketは「天気予報をAPIで配信」してくれる会社です。無料のトライアルもあるようですので、試してみるのに敷居が低いかと思います。

LifesocketのAPI一覧を以下に載せます。

  1. ① 天気予報・生活指数取得API
  2. ② 気象観測データAPI
  3. ③ 熱中症指数API
  4. ④ 高解像度降水予測API
  5. ⑤ 気象情報Javascriptマップサービス

ここでは、①天気予報APIと②気象観測データAPIにアクセスしてデータを取得してみます。

LifesocketのAPIにアクセスしてデータを取得するためには、アクセスキーが必要になります。無料のトライアルでもアクセスキーが取得できると思いますので、HPから取得方法を確認して、試してみてください。

2.2.1. Lifesocketの天気予報API

Lifesocketの天気予報APIは2種類あります。

  1. 1) 日毎の天気予報を取得できるAPI
  2. 2) 1時間ごとの天気予報を取得できるAPI

仕様の詳細は、HPにLifesocket-API仕様書がありますので、そちらで確認してください。ここでは、必要最低限の仕様を示してデータを取得してみます。

2.2.1.1. 日毎の天気予報APIからデータの取得

日毎の天気予報APIの仕様の抜粋を示します。最大10日までの天気予報が取得できるようです。

APIのアドレスは、

https://www.life-socket.jp/api/v1/weather/{PinpointCode}?days=5

です。アクセスするためには、ピンポイントコードと呼ばれる地域固有の番号が必要になります。

滋賀県のピンポイントコードを次に記します。ピンポイントコードを指定したら必ずそこ住所の天気予報が取得できるというわけではなく、天気予報の情報がある一番近い場所の天気予報が表示されます。そこは注意です。

Node-REDの術例を以下に示します。

  1. ① インジェクトノードを配置します。そして、msg.payloadにピンポイントコードを数形式で入力します。
  2. ② changeノードを配置します。そして、msg.payloadのピンポイントコードをmsg.postsに代入します。
  3. ③ functionノードを配置します。そして、msg.headersにアクセスキーを記載します。
                 msg.headers = {“x-access-key”:”Lifesocketから入手したアクセスキー”};
  4. ④ http requestノードを配置します。そして、メソッドに”GET”を選択します。
  5. ⑤ http requestノードのURLにAPIアドレスを記載します。
       https://www.life-socket.jp/api/v1/weather/{{post}}?days=5
  6. ⑥ http requestノード出力をモニターするためにDebugノードを配置します。

以上の記載がおわったら、Deployします。そして、いずれかのインジェクトノードを押すと、天気予報が返ってきます。

days=1として、1日分をリクエストした場合の例の例を以下に示します。dailyのデータがarray[1]で1日分のみ帰ってきてます。

days=5として、5日分をリクエストした場合の例の例を以下に示します。dailyのデータがarray[5]で5日分が帰ってきてます。

2.2.1.2. 1時間毎の天気予報APIからデータの取得

1時間ごとの天気予報APIの仕様の抜粋を示します。最大52時間先(2日と4時間)までの天気予報が取得できるようです。

APIのアドレスは、

https://www.life-socket.jp/api/v1/weather/hourly/{PinpointCode}?hours=52

です。アクセスするためには、こちらもピンポイントコードと呼ばれる地域固有の番号が必要になります。また、日毎のdaysの代わりに、hoursで時間を指定するようになっています。

Node-REDの記述例を以下に示します。

日毎のNode-REDの記述からの変更点は、APIアドレスのみです。

・http requestのURLの中身を書き換えてください。

 

書き換えが終わったら、Deployをして、いずれかのインジェクトボタンを押してください。

1時間予報が表示されます。この例では、hours=52としているので、52時間分の天気予報が表示されています。Hourlyとしてarray[52]個、52時間分が返ってきています。

2.2.2. Lifesocketの気象観測データAPI

以下に、Lifesocketの気象観測データAPIの仕様の抜粋を示します。気象観測データでは、ピンポイントコードの他にデータ取得開始日時と終了日時が指定、取得するデータを指定できます。1時間ごとの気象観測データを取得できます。また、7日前までしか取得できませんので、注意が必要です。

取得できるデータの一覧をAPIの仕様の次に示します

それでは、次に、Node-REDでの気象観測データの取得例を示します。

ここでの変更点は、

  1. ① StartTimeとEndTimeの設定。ここでは、インジェクトが押された際の日時をInputとしています。StartTimeは現時点の日時から-7日しています。
  2. ② http requestのAPIアドレスを変更しています。
      https://www.life-socket.jp/api/v1/amedas/{{post}}?StartTime={{StartTime}}&EndTime={{EndTime}}

StartTimeとEndTimeの設定を次に示します。

以上を入力したら、Deployをして、いずれかの地域のインジェクションノードのボタンを押します。

すると、7日館前までの1時間ごとの気象観測データが出力されます。7日間×24時間/日=168時間となりますので、上のNode-REDの図の右側のデバッグ欄には、Element[168]として168時間分の気象観測データが出力されています。

以上で、民間の気象サイトのAPIを使ったデータ取得法の説明を終了します。次からは、この取得したデータをグラフに表示する方法に関して説明します。

3.気象サイトのデータのグラフ表示

グラフの表示は、Plotlyというライブラリを使って行います。Plotlyを使ったグラフ表示方法の詳細説明は、応用事例「データベースに蓄えたデータでグラフを描こう!!」を参照してください。基本的に気象サイトをデータベースと考えれば、APIアドレスを気象サイトんに送ることは、Query文をデータベースに送ることと同じと考えられます。したがって、ここまで述べてきた気象サイトからの気象データの取得と「データベースに蓄えたデータでグラフを描こう!!」でのグラフ表示を組み合わせれば、良いだけです。

やることの基本は、配列として送られてきたデータを、配列のmap関数を使ってそれぞれに分離して表示用のデータ配列に入れるだけです。

ここでは、2つの例を示します。

  1. ① 過去7日間の気象観測データから気温の変化をグラフ化します。
  2. ② 1時間毎の天気予報データから、関心の高い気温、降水確率、湿度をグラフ化してみます。

 3.1. 過去7日間の気温観測データのグラフ化

次に、過去7日間の気温観測データのグラフ化をするための、Node-REDのフローを示します。基本的なところは、応用事例「データベースに蓄えたデータでグラフを描こう!!」の「3.Node-REDのフローの作成」の図と同じです。

大きく①データ取得部と②グラフ化部でベースが構成されています。

3.1.1. データ取得部

まずデータ取得部の説明をします。ここでは、気象サイドに送信するAPIアドレスを生成します。http requetに記載するAPIアドレスは以下です。

        https://www.life-socket.jp/api/v1/amedas/{{post}}?StartTime={{StartTime}}&EndTime={{EndTime}}

mst.postにピンポイントコードを、msg.StartTimeとmsg.EndTImeにそれぞれ開始時間と終了時間を設定します。msg.EndTimeが現時点の日時で、msg.StartTimeは、7日前の日時にします。ピンポイントコードは、dashboardのドロップダウンノードで選択できるようにします。

以下、Node-REDのフロー図との対応で説明します。

  1. ③ Plotlyライブラリロードは、Plotlyのライブラリをロードする部分で、「3.2.1. Node-REDへのPlotlyライブラリのロード記述追加」に記載がありますので、そのまま対応していただければOKです。
  2. ④のピンポイントコード設定は、dashboard画面で、エリアを選択できるように、dashboardのドロップダウンノードを使用しています。初期設定でNode-REDが起動したときに、大津が設定されるようにしています。地域を選ぶと次に配置されたchangeノードで、ピンポイントコードをflow.pinPointCodeに代入しています。flow宣言された変数は、そのフローもしくはタブの中でどのノードからもアクセスできます(変数のスコープがノード単独から、タブもしくはフローに広がります)。
  3. ⑤ ライセンス明記です。Lifesocketのデータを使用している旨を明記するためのtextノードです。
  4. ⑥ 温度取得ボタン、dashboardのボタンノードを配置しています。dashboardでボタンを押すことで、気象サイトへのAPIアドレス送信が始まります。ここでは、ボタンが押されたときに、msg.payloadにその時の日時を設定しています。
  5. ⑦ その次のchangeノードで、msg.payloadに入っている日時をmsg.topicに代入し、flow.pinPointCodeをmsg.payloadに代入します。

3.1.2. グラフ化部

3.1.2.1. グラフ化部の変更点

グラフ化部は、基本HTMLコードで記載します。「3.2. グラフ化部の作成:Node-REDのダッシュボードでグラフ化」と異なる所のみ説明します。

異なる点の1点目は、気象サイトから帰ってきたデータのarrayの名称です。

「3.2. グラフ化部の作成:Node-REDのダッシュボードでグラフ化」では、名前が無くいきなりarray[168]とかでした。今回は、Element.array[167]とElementという名前が付いています。

そのため、HTMLコードの記述にElementという名称が含まれます。

例えば、msg.payloadに送られてきたデータが有効であるかどうかを調べる箇所です。current(=msg.payload).Element.length !==0 でmsg.payloadに含まれるElementと言う名称の配列のサイズがゼロでなかったらというように見ています。

if (current.Element && current.Element.length !== 0) {
    scope.send({tag: 0});
    plot(current);
} else {
    scope.send({tag: 1});
    Plotly.purge('plot');
}

また、グラフ化するデータを作成する部分でも、map関数を呼ぶ際にcurrent.Element.map()として呼んでいます。

var time = current.Element.map(function(value){return new Date(value.DateTime)});
var temp = current.Element.map(function(value){return(value.Temperature)});

「3.2. グラフ化部の作成:Node-REDのダッシュボードでグラフ化」では、それぞれ、

if (current && current.length !== 0) {
var time = current.map(function(value){return new Date(value.datetime)});
var temp = current.map(function(value){return(value.data0)});

となっていました。

異なる点の2点目は、同じくグラフ化するデータを作成する部分です。帰ってくるデータの名称が異なるので、ここでは、DateTimeとTemperatureとなっています。もとは、datetimeとdata0でした。

var time = current.Element.map(function(value){return new Date(value.DateTime)});
var temp = current.Element.map(function(value){return(value.Temperature)});
3.1.2.2. グラフ化部のHTMLコード

グラフ化部のHTMLコードを次に示します。参考にしてください。

<div id="plot" style="height: 574px"></div>
<script>
  (function(scope) {

    // msg.payloadのデータを監視する
    scope.$watch('msg.payload', (current) => {
      if (current == null) {
        return;
      }
      if (typeof current !== 'object') {
        return;
      }

      if (current.Element && current.Element.length !== 0) {
        scope.send({tag: 0});
        plot(current);
      } else {
        scope.send({tag: 1});
        Plotly.purge('plot');
      }
    });

    // グラフを描画する
    function plot(current) {

      var time = current.Element.map(function(value){return new Date(value.DateTime)});
      var temp = current.Element.map(function(value){return(value.Temperature)});
      var data = {
        x:time,
        y:temp,
        name:'気象データ',
        mode: 'lines',
        type: 'scattergl',
        line: {
          width: 2
        }
      }

      const layout = {
        title: "温度ログ",
        xaxis: {
          title: '時間'
         },
        yaxis: {
          title: '温度[℃]'
        },
      };

      Plotly.newPlot('plot', [data], layout);
    }
  })(scope);
</script>
3.1.2.3. グラフ化の結果

地域ををドロップダウンリストから選んで、温度取得ボタンを押すと、下記の様に過去7日間分の気温がグラフ化されます。

3.2.1時間毎の天気予報データから気温、降水確率、湿度をグラフ化

次に、気象サイトの天気予報データから気温と降水確率、温度をグラフ化してみます。完成グラフはアイキャッチ画像です。

3.2.1.データ取得部

いつものようにNode-REDのフローを示します。

データ取得部は、「2.2.1.2. 1時間毎の天気予報APIからデータの取得」のままです。ピンポイントコードをドロップダウンリストから得レベルようにしているところが異なるだけです。

3.2.2.グラフ化部

3.2.2.1. グラフ化部の相違点

データ取得部は、今までと異なって、グラフに3本のラインを引きます。上の図にあるように、Hourly.temperature, Hourly.RainPercentage, Hourly.Humidityの3つのデータです。

3本の線になっても基本の考え方は同じです。配列のmapメソッドを使って、データ配列を分離します。

var time = current.Hourly.map(function(value){return new Date(value.DateTime)});
var temp = current.Hourly.map(function(value){return(value.Temperature)});
var rain = current.Hourly.map(function(value){return(value.RainPercentage)});
var humd = current.Hourly.map(function(value){return(value.Humidity)});

そして、Plotlyをコールする際には、

Plotly.newPlot('plot', [data1,data2,data3], layout);

というように3つのデータをカギ括弧でくくってPlotlyに渡します。

そのために、

data1, data2, data3というJSONコードを作成します。

var data1 = {
  x:time,
  y:temp,
  name:'温度[℃]',
  mode: 'lines',
  type: 'scattergl',
  line: {
    width: 2
  }
}
var data2 = {
  x:time,
  y:rain,
  name:'降水確率[%]',
  mode: 'lines',
  type: 'scattergl',
  yaxis: 'y2',
  line: {
    width: 2
  }
}
var data3 = {
  x:time,
  y:humd,
  name:'湿度[%]',
  mode: 'lines',
  type: 'scattergl',
  yaxis: 'y2',
  line: {
    width: 2
  }
}
3.2.2.2. グラフ化部のHTMLコード

次に、グラフ化部のHTMLコードを示します。

<div id="plot" style="height: 574px"></div>
<script>
  (function(scope) {

    // msg.payloadのデータを監視する
    scope.$watch('msg.payload', (current) => {
      if (current == null) {
        return;
      }
      if (typeof current !== 'object') {
        return;
      }

      if (current.Hourly && current.Hourly.length !== 0) {
        scope.send({tag: 0});
        plot(current);
      } else {
        scope.send({tag: 1});
        Plotly.purge('plot');
      }
    });

  // グラフを描画する
      function plot(current) {

        var time = current.Hourly.map(function(value){return new Date(value.DateTime)});
        var temp = current.Hourly.map(function(value){return(value.Temperature)});
        var rain = current.Hourly.map(function(value){return(value.RainPercentage)});
        var humd = current.Hourly.map(function(value){return(value.Humidity)});
        var data1 = {
          x:time,
          y:temp,
          name:'温度[℃]',
          mode: 'lines',
          type: 'scattergl',
          line: {
            width: 2
          }
        }
        var data2 = {
          x:time,
          y:rain,
          name:'降水確率[%]',
          mode: 'lines',
          type: 'scattergl',
          yaxis: 'y2',
          line: {
            width: 2
          }
        }
        var data3 = {
          x:time,
          y:humd,
          name:'湿度[%]',
          mode: 'lines',
          type: 'scattergl',
          yaxis: 'y2',
          line: {
            width: 2
          }
        }

       const layout = {
        title: "温度ログ",
        xaxis: {
          title: '時間'
        },
        yaxis: {
          title: '温度[℃]',
          range:[-10, 40]
        },
        yaxis2: {
          title: '降水確率、湿度[%]',
          range:[0,100],
          overlaying: 'y',
          side: 'right'
        },
      };

      Plotly.newPlot('plot', [data1,data2,data3], layout);
    }
  })(scope);
</script>
3.2.2.3. グラフ化の結果

地域ををドロップダウンリストから選んで、温度取得ボタンを押すと、下記の様に52時間の天気予報がグラフ化されます。