9/21の enebular アップデートで、それまで有料だった3つの機能がFreeプランでも使用できるようになりました。この記事では、3つの機能のうちファイルアセットについて説明します。
ファイルアセットは、enebular-agentをインストールしたデバイスにファイルをデプロイする機能です。デプロイするファイルに特別な制約はありません。設定ファイルやスクリプトファイルなど、さまざまなファイルがデプロイできます。工夫次第でいろいろな応用ができるenebularの重要な機能です。
今回は、このファイルアセットを設定ファイルとして使用してみます。 ファイルアセットをデプロイすることで、設定内容を自由に変更することができます。
ここでは、内閣官房が新型コロナウィルス感染症対策の一環として公開しているオープンデータのAPIを利用して、都道府県別の感染者数を取得する仕組みを作成します。対象の都道府県は、設定ファイルにして自由に変更できるようにします。この設定ファイルを、ファイルアセットとして作成することにします。
新型コロナウィルス感染症対策ページ
「新型コロナウィルス感染症対策ページ」は内閣官房が公開しているWebページです。このページに感染者数を取得するためのAPIの解説があります。詳しい情報を確認したい方は、このページを参照してください。
全国の感染者数のオープンデータは以下のAPIで取得可能で、データはJSON形式で得られます。ここで提供されているAPIは、認証も不要で簡単に利用できます。
クエリ文字列として都道府県名や日付を指定することで、データの絞り込みを行うことができます。
https://opendata.corona.go.jp/api/Covid19JapanAll?dataName=石川県&date=20210101
目次
作成するもの
作成する仕組みを、もう少し詳しく決めます。
- 1日に1回、対象の都道府県(複数指定可能)の最新の感染者数をAPI
https://opendata.corona.go.jp/api/Covid19JapanAll
から取得する ※1 - 取得した感染者数は、CSVファイルに保存する ※2
- 対象の都道府県は、設定ファイル(CSVファイル)に記載しておく
※1 確認した範囲では、APIから取得できる最新データは、3日ほど前のデータのようです。ここでは、3日前のデータを取得することにします。
※2 APIから得られる感染者数データはJSON形式ですが、後から加工するためにCSVファイルとして保存することにします。
環境作成
以下の手順で、enebularとenebular-agentが動作する環境を作成します。
- enebular-agentが動作するデバイスを準備する
- enebularアカウントとAWSアカウントを作成する
- enebular-agentをインストールする
1. enebular-agentが動作するデバイスを準備する
enebular-agentを動作させるデバイスは、Rhaspberry Piが最もポピュラーです。
enebular-agentは、Debian GNU/Linuxが動作する環境ならインストール可能で、さまざまな環境で動作します。好きな環境で試してみてください。Linuxが動作しているPCや、VirtualBoxなどの仮想環境でも構いません。(ちなみに、筆者はMac Book Pro上のVagrant + VirtualBox環境で開発をしました)
2. enebular アカウントと AWS アカウントを作成する
enebular-agentを利用するためには、enebularのアカウントとAWSのアカウントが必要になります。以下の手順を参考にしてサインアップしてください。
enebular へのサインアップ
AWS へのサインアップ
3. enebular-agentをインストールする
デバイスが準備できたら、enebular-agentをインストールします。enebular-agentインストール手順(オンラインマニュアル)の手順にしたがってインストールしてください。
enebular-agentインストール手順は少し複雑です。下のQiitaの記事が、分かりやすい補助資料になりそうなので紹介します。
Node-REDフローの作成
Node-REDのフロー(JSONファイル)を添付します。フローエディタにインポートして使用してください。
[{"id":"5c5c1496.af809c","type":"inject","z":"1e79e8d5.d84bc7","name":"daily job","topic":"","payload":"","payloadType":"date","repeat":"86400","crontab":"","once":true,"onceDelay":0.1,"x":120,"y":100,"wires":[["80386e67.2388f"]]},{"id":"80386e67.2388f","type":"file in","z":"1e79e8d5.d84bc7","name":"Prefectures","filename":"/home/enebular/enebular-runtime-agent/ports/awsiot/assets/pref.csv","format":"utf8","chunk":false,"sendError":false,"encoding":"none","x":290,"y":100,"wires":[["4c392ccd.c72cc4"]]},{"id":"4c392ccd.c72cc4","type":"csv","z":"1e79e8d5.d84bc7","name":"convert to csv","sep":",","hdrin":"","hdrout":"","multi":"one","ret":"\\n","temp":"","skip":"0","strings":true,"x":480,"y":100,"wires":[["207e478e.7f7c08"]]},{"id":"207e478e.7f7c08","type":"split","z":"1e79e8d5.d84bc7","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":650,"y":100,"wires":[["8df54403.6f4218"]]},{"id":"8df54403.6f4218","type":"change","z":"1e79e8d5.d84bc7","name":"prepare url","rules":[{"t":"set","p":"date","pt":"msg","to":"$fromMillis($millis() - 24 * 60 * 60 * 1000 * 3, '[Y0001][M01][D01]')","tot":"jsonata"},{"t":"set","p":"payload","pt":"msg","to":"$encodeUrl(payload)\t","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":190,"y":200,"wires":[["cd0b8d32.ea487"]]},{"id":"a77c94b5.1c34d8","type":"http request","z":"1e79e8d5.d84bc7","name":"","method":"GET","ret":"obj","paytoqs":false,"url":"","tls":"","persist":false,"proxy":"","authType":"","x":510,"y":200,"wires":[["eda8813b.c03e4"]]},{"id":"18111fe8.5c19f","type":"file","z":"1e79e8d5.d84bc7","name":"covid19.csv","filename":"/home/enebular/enebular-runtime-agent/ports/awsiot/assets/covid19.csv","appendNewline":true,"createDir":false,"overwriteFile":"false","encoding":"none","x":590,"y":300,"wires":[["cabd132f.e8a82"]]},{"id":"cabd132f.e8a82","type":"debug","z":"1e79e8d5.d84bc7","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":770,"y":300,"wires":[]},{"id":"cd0b8d32.ea487","type":"template","z":"1e79e8d5.d84bc7","name":"set url","field":"url","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"https://opendata.corona.go.jp/api/Covid19JapanAll?&dataName={{payload}}&date={{date}}","output":"str","x":350,"y":200,"wires":[["a77c94b5.1c34d8"]]},{"id":"eda8813b.c03e4","type":"change","z":"1e79e8d5.d84bc7","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.itemList[0]","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":700,"y":200,"wires":[["cc064bac.1178d8"]]},{"id":"cc064bac.1178d8","type":"split","z":"1e79e8d5.d84bc7","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":290,"y":300,"wires":[["214661ad.54caae"]]},{"id":"214661ad.54caae","type":"join","z":"1e79e8d5.d84bc7","name":"","mode":"custom","build":"string","property":"payload","propertyType":"msg","key":"topic","joiner":",","joinerType":"str","accumulate":false,"timeout":"","count":"3","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":430,"y":300,"wires":[["18111fe8.5c19f"]]}]
インポートするとエディタ上では、図のようになります。
出来上がったフローは保存してください。ここでは、free-fileasset-demo-flow
という名称でフローを保存することとします。それでは、フローの中身を確認していきます。
フローの起動 (Inject)
Injectノードを利用して、1日に1回フローを起動します。下図は毎日12:00にフローを起動する設定です。好きな時間に変更してください。
対象都道府県名の取得 (File-in, CSV, Split)
Injectノードに続く3つのノードは、後述する設定ファイル(CSVファイル)から都道府県名を取得する処理です。
File-inノードは、デプロイされたファイルアセット(pref.csv
)を読み込んで、msg.payloadとして次のノードに渡します。ここでは、Filenameを以下のように設定しています。他の設定はデフォルトのままです。
/home/enebular/enebular-runtime-agent/ports/awsiot/assets/pref.csv
続くCSVノードは、受け取ったファイルの内容(msg.payload)をCSVとして解釈して、これをJavaScriptのオブジェクトに変換します(下図のようなオブジェクトになります)。このCSVノードは、デフォルト設定のまま使用しています。特別な設定は行わず、ノードを配置して前後のノードと接続しています。
{ col1: "東京都", col2: "大阪府", ... }
最後のSplitノードは、受け取ったJavaScriptのオブジェクトをバラバラのStringオブジェクトに分割してくれます。これで、設定ファイルの中に列挙された都道府県名を1つずつ扱うことができるようになりました(下図)。このSplitノードもCSVノードと同様に、デフォルト設定のまま使用しています。
東京都
大阪府
感染者数の取得 [API呼び出し] (Change, Template, Http-request, Change)
2段目の処理は、APIを呼び出して感染者数を取得する処理です。
最初のChangeノードでは、API呼び出しに必要な都道府県名と日付の文字列を準備します。 都道府県の文字列はすでにmsg.payload
に格納されていますが、日本語の形になっています。$encodeUrl()
関数で、URLとして扱えるようにエンコードします。関数の引数では、msg
部分は省略できますので注意してください。
$encodeUrl(payload)
日付の文字列は、msg.date
に格納します。下図のように設定してください。設定する文字列は以下の通りです。
$fromMillis($millis() – 24 * 60 * 60 * 1000 * 3, ‘[Y0001][M01][D01]’)
$millis()
関数でその時点のUnixエポックを取得します。そこから3日前のデータを取得しますので、ミリ秒単位で3日分を引き算します(24時間x60分x60秒x1000ミリ秒x3日)。
これを$fromMillis()
関数で文字列に変換します。[Y0001][M01][D01]
は、文字列変換のフォーマットを示していて、この場合は"20211224"
のように8桁の数字になります。
次にTemplateノードでURLを整形します。 Http-requestノードは、msg.url
に設定されたURLにhttpリクエストを送信しますので、URLはmsg.url
に設定します(下図のProperty欄)。
設定するTemplateは以下の通りです。payload
にはURLエンコードされた都道府県名が格納されています。date
には3日前の日付文字列が格納されています。
https://opendata.corona.go.jp/api/Covid19JapanAll?&dataName={{payload}}&date={{date}}
実際に出力されるURLは以下のように、URLエンコードされた文字列になります。
https://opendata.corona.go.jp/api/Covid19JapanAll?&dataName=%E7%A6%8F%E4%BA%95%E7%9C%8C&date=20211224
Http-requestノードは、出力形式 (Return) をJSONオブジェクト (a parsed JSON object) にしてください。
最後のChangeノードでは、Http-requestノードから受け取ったJSONオブジェクトから感染者のデータ部分だけを取り出します。下図のように設定してください。
JSONオブジェクトの形は以下のようになっています。この中のitemListの中身を取得します。
{
errorInfo: {
errorFlag: "0",
errorCode: null,
errorMessage: null,
},
itemList: [
{
date: "2021-12-24",
name_jp: "東京都",
npatients: 1,
},
],
}
感染者数の記録 (Split, Join, File-out)
最後の段では、取得した感染者数データをCSVファイルにして保存します。
最初のSplitノードでは、前述の通り、取り出したitemListの中身のdate
, name_jp
, npatients
それぞれをバラバラにします。 このSplitノードは、デフォルトの動作のまま使用しています。特別な設定は行わず、ノードを配置して前後のノードと接続しています。
次のJoinノードでは、SplitでバラバラにしたデータをCSV形式で繋ぎなおします。動作(Mode)を手動(manual)
にして、連結文字(joined using)を","
に設定します。また、指定数のメッセージパーツ (After a number of message parts) を受信後のを"3"
に設定してください。
Fileノードは、ファイルに1行ずつデータを追加します。Joinノードからは1つの都道府県の1日分のデータが送られてきます。これを1行としてファイルに追加していきます。ここでは、Filenameを以下のように設定しています。他の設定はデフォルトのままです。
/home/enebular/enebular-runtime-agent/ports/awsiot/assets/covid19.csv
フローが実行されると、以下のようなファイルが作成されます。
2021-12-24,東京都,0
2021-12-24,大阪府,0
2021-12-24,福井県,0
...
ファイルアセットの作成
感染者数データ収集対象の都道府県は、設定ファイルで自由に決められるようにします。この設定ファイルは、CSVファイルとして作成します。さらにCSVファイルをファイルアセットにして、enebular-agentにデプロイできるようにします。
CSVファイルの作成
まず、以下のようなファイルを作成してください。カンマの前後に空白などは入れないでください。 作成したファイルは、pref.csv
というファイル名で保存します。(Node-REDフローではpref.csv
を読み込みますので、ファイル名は変更しないでください)
東京都,大阪府,福井県,和歌山県
※ enebularを開発しているウフルのオフィスがある都道府県です 😉
ファイルデプロイ結果の確認方法
前述のpref.csv
ファイルを元にしてファイルアセットを作ります。
enebularにログインして、プロジェクトを選択したら、マニュアルのファイルの登録にしたがってpref.csv
を登録してください。
ファイルアセットの名前は、自由に設定していただいて構いません。この記事では、仮にfree-fileasset-demo-csv
とします。ファイルアセットにはさまざまな設定項目がありますが、今回は使いませんので設定不要です。
デプロイ
ファイルのデプロイ
ファイルアセットをenebular-agentにデプロイします。Node-REDフローはpref.csv
を読み込んで動作しますので、先にファイルをデプロイしてください。
ファイルデプロイの方法は、マニュアルのファイルのデプロイに詳しく記述されていますので、ここでは概要を説明します。
- enebularのダッシュボードから、ファイルアセット
free-fileasset-demo-csv
を選択します - ファイルアセットのOverview画面には、”Deploy”ボタンがありますので押してください
- Connectionを選択します。Connectionの一覧から、上述の環境作成でenebular-agentをインストールした際に使用したConnectionを選びます
- Targetデバイスを選択します。デバイスの一覧から、上述の環境作成で指定したデバイス名を選びます
ファイルデプロイ結果の確認方法
ファイルが正しくデプロイされたかどうか、最初はどうしても気になりますね。デプロイされたファイルは、/home/enebular/enebular-runtime-agent/ports/awsiot/assets
に保存されます。したがって、上記のファイルデプロイでは、/home/enebular/enebular-runtime-agent/ports/awsiot/assets/pref.csv
というファイルができているはずです。デプロイ先のデバイスにログインして確かめることができます。
フローのデプロイ
Node-REDフローをデプロイします。
enebular-agentへのフローのデプロイの方法は、マニュアルのAWS IoTへのデプロイに詳しく記述されていますので、ここでは概要を説明します。
- enebularのダッシュボードから、フロー
free-fileasset-demo-flow
を選択します - フローのOverview画面には、”Deploy”ボタンがありますので押してください
- Connectionを選択します。Connectionの一覧から、上述の環境作成でenebular-agentをインストールした際に使用したConnectionを選びます
- Targetデバイスを選択します。デバイスの一覧から、上述の環境作成で指定したデバイス名を選びます
以上の手順で、フローがデプロイされます。
動作確認
フローが正しく動作すると、/home/enebular/enebular-runtime-agent/ports/awsiot/assets/covid19.csv
というファイルが作成されます。内容を確認してみましょう。ファイルのあるフォルダに移動して、sudo cat covid19.csv
とコマンドを実行してください。
2021-12-24,東京都,0
2021-12-24,大阪府,0
2021-12-24,福井県,0
...
上記のように出力されていれば成功です。対象の都道府県を変更したい場合は、pref.csvを変更してデプロイし直してください。
さいごに
CSVファイルをファイルアセットとして、enebular-agentにデプロイして、Node-REDフローの設定ファイルとして使用する方法を説明しました。
この記事では、CSVファイルが出力されるフローを作成しましたが、このままでは少し面白くないですね。次の記事では、CSVファイルからグラフを作る処理を作成します。