以前の記事「設定ファイルをIoTデバイスにデプロイする方法」に引き続き、9/21の enebular のアップデートで無料で使えるようになった”ファイルアセット”の使い方について説明します。
「設定ファイルをIoTデバイスにデプロイする方法」では、設定ファイル(CSVファイル)をファイルアセットにして、enebular-agentにデプロイしました。ファイルアセットを使うと、スクリプトをenebular-agentにデプロイして実行することもできます。
この記事では、Pythonのスクリプトを作成して、enebular-agentにデプロイして実行します。スクリプトを実行させることで、Node-REDでは難しいことも、より自由に実現できるようになります。
目次
作成するもの
この記事で作成する機能を説明します。
「設定ファイルをIoTデバイスにデプロイする方法」の記事では、新型コロナウィルスの感染者数をAPIから取得して、CSVファイルに記録しました。
今回は、Pythonのスクリプトを作成して、感染者数のCSVファイルからグラフを作成します。さらに作成したグラフを、Node-REDを利用してGoogle Driveにアップロードしてみます。
準備
Python
enebular-agentがインストールされたデバイスには、Pythonがインストールされている必要があります。今回作成するPythonのスクリプトは、Python2でもPython3でも動作しますので、どちらのバージョンがインストールされていてもかまいません。
また、以下のパッケージをあらかじめインストールしておいてください。パッケージのバージョンは、筆者の手元のバージョンを確認しているだけですので、あまり厳密ではありません。
- matplotlib >= 1.3.1
- numpy >= 1.16.6
Debianの場合、apt-getコマンドでインストールできますので、以下のようなコマンドでインストールできます(環境によってはsudoが必要かもしれません)。
apt-get install python-matplotlib
apt-get install python-numpy
Google Drive
この記事では、作成したグラフをGoogle Driveにアップロードします。Googleアカウントを作成して、Google Driveが使える状態にしておいてください。
Node-REDでGoogle Driveにファイルをアップロードする手順については、以下のQiitaの記事がとても分かりやすく参考になります。
「Node-RedからGoogle Driveに画像ファイルをアップロードする」 @imanao89
この記事を参考にして、 “1. Google Developer Consoleで APIの有効化・サービスアカウント作成し、JSONファイルをダウンロード” と “2. Google Driveでフォルダを作成し、フォルダを先ほど作成したサービスアカウントに共有する” までを実行しておいてください。
実行ファイルの作成
Pythonのスクリプトを作成します。
以下のプログラムを、plot.py
というファイル名で作成して保存してください。
#!/usr/bin/env python
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
from datetime import datetime as dt
data = np.loadtxt('/home/enebular/enebular-runtime-agent/ports/awsiot/assets/covid19.csv', delimiter=',', dtype='str')
prefs = np.loadtxt('/home/enebular/enebular-runtime-agent/ports/awsiot/assets/pref.csv', delimiter=',', dtype='str')
for pref in prefs.tolist():
dates = []
patients = []
for line in data.tolist():
if line[1] == pref:
patients.append(line[2])
dates.append(dt.strptime(line[0], '%Y-%m-%d'))
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.plot(dates, patients)
fig.savefig(pref + ".png")
とても簡単なプログラムですので、簡潔に内容を説明してみます。
data
変数には、前回の記事で作成した感染者数CSVファイル(covid19.csv
)を読み込みます。感染者数CSVファイルの中身は、以下のようになっています。
2021-12-24,東京都,0
2021-12-24,大阪府,0
2021-12-24,福井県,0
...
prefs
変数には、前回の記事で作成したデータ収集対象の都道府県名ファイル(prefs.csv
)を読み込みます。都道府県名ファイルの中身は、以下のようになっています。
東京都,大阪府,福井県,和歌山県
外側のforループで、都道府県毎に処理をおこないます。
内側のforループで、dates
変数に日付のデータ(CSVファイルの1列目)、patients
変数に感染者数のデータ(CSVファイルの2列目)をlistデータとして格納します。
データの格納が終わったら、dates変数を横軸、patients変数を縦軸にして折れ線グラフを作成します(ax.plot(dates, patients)
)。
さらに作成したグラフをPNGファイルとして保存します(fig.savefig(pref + ".png")
)。ここでは、[都道府県名].png
という形のファイル名になります (例: 東京都.png)。
ファイルのデプロイ
ファイルアセットの作成
上述のplot.py
ファイルを元にしてファイルアセットを作ります。
enebularにログインして、プロジェクトを選択したら、マニュアルのファイルの登録にしたがってplot.py
を登録してください。ファイルアセットの名前は、自由に設定していただいて構いません。この記事では、仮にfree-fileasset-demo-python
とします。
次にExecution On Deploy
ボタンをONにしてください。このボタンをONにすると、ファイルのデプロイ後にそのファイルを実行ファイルとみなして実行します。今回は他の設定項目はデフォルトのままで構いません。
各設定項目の詳しい説明は、マニュアルのファイル設定に記載されていますので参考にしてください。
ファイルのデプロイ
ファイルアセットfree-fileasset-demo-python
をenebular-agentにデプロイします。前回の記事で作成したフローを実行して、感染症者数CSV(covid19.csv)が作成されていることが前提条件となります。
ファイルデプロイの方法は、マニュアルのファイルのデプロイに詳しく記述されていますので、ここでは概要を説明します。
- enebularのダッシュボードから、ファイルアセット
free-fileasset-demo-python
を選択します - ファイルアセットのOverview画面には、”Deploy”ボタンがありますので押してください
- Connectionを選択します。Connectionの一覧から、上述の環境作成でenebular-agentをインストールした際に使用したConnectionを選びます
- Targetデバイスを選択します。デバイスの一覧から、上述の環境作成で指定したデバイス名を選びます
以上の手順で、ファイルがデプロイされて実行されます。
エラーがなければ、東京都.png
、大阪府.png
、福井県.png
、和歌山県.png
のようなファイルができるはずです。(ファイルができるフォルダは、/home/enebular/enebular-runtime-agent/ports/awsiot/assets
です。/home/enebular/
部分はインストール時に指定するユーザーによって変化するので注意してください。)
Node-REDフローの作成
次に作成したグラフをGoogle Driveにアップロードするために、Node-REDフローを作成します。
node-red-contrib-googleノードのインストール
ファイルをGoogle Driveにアップロードするために、node-red-contrib-googleノードを利用します。
enebularでフローを作成して、フローエディタを起動してください。フローは、free-fileasset-demo-drive
という名称でフローを保存することにします。
フローエディタのメニューからmanage palette
を選択します。
Installタブに移動して、node-red-contrib-google
ノードを検索し、Install
ボタンを押してインストールしてください。
フローのインポート
Node-REDのフロー(JSONファイル)を添付します。フローエディタにインポートして使用してください。
[{"id":"f5e33834.322d98","type":"tab","label":"Flow 1","disabled":false,"info":""},{"id":"e7039725.da7188","type":"debug","z":"f5e33834.322d98","name":"","active":true,"tosidebar":true,"console":true,"tostatus":false,"complete":"payload","targetType":"msg","x":820,"y":100,"wires":[]},{"id":"3ed33059.2858d","type":"change","z":"f5e33834.322d98","name":"set param","rules":[{"t":"set","p":"folderid","pt":"msg","to":"16XagCyMW9wkCczhNo9H0FtWyPhN6tdhF","tot":"str"},{"t":"set","p":"filename","pt":"msg","to":"convi19.csv","tot":"str"},{"t":"set","p":"mimeType","pt":"msg","to":"text/plain","tot":"str"},{"t":"set","p":"payload","pt":"msg","to":"{\t \"resource\": {\t \"name\": filename,\t \"parents\": [\t folderid\t ]\t },\t \"media\": {\t \"mimeType\": mimeType,\t \"body\": payload\t },\t \"fields\": \"id\"\t}","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":500,"y":100,"wires":[["42b4ad6a.63db74"]]},{"id":"148ae79b.9fcd18","type":"file in","z":"f5e33834.322d98","name":"covid19.csv","filename":"/home/enebular/enebular-runtime-agent/ports/awsiot/assets/covid19.csv","format":"utf8","chunk":false,"sendError":false,"encoding":"none","x":330,"y":100,"wires":[["3ed33059.2858d"]]},{"id":"44029edd.72b5c","type":"inject","z":"f5e33834.322d98","name":"kick upload","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":true,"onceDelay":"30","x":150,"y":100,"wires":[["4a3d3636.209108","148ae79b.9fcd18"]]},{"id":"4a3d3636.209108","type":"file in","z":"f5e33834.322d98","name":"Prefectures","filename":"/home/enebular/enebular-runtime-agent/ports/awsiot/assets/pref.csv","format":"utf8","chunk":false,"sendError":false,"encoding":"none","x":210,"y":180,"wires":[["87414b13.768898"]]},{"id":"87414b13.768898","type":"csv","z":"f5e33834.322d98","name":"convert to csv","sep":",","hdrin":"","hdrout":"","multi":"one","ret":"\\n","temp":"","skip":"0","strings":true,"x":400,"y":180,"wires":[["413b1f19.4cce2"]]},{"id":"413b1f19.4cce2","type":"split","z":"f5e33834.322d98","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":570,"y":180,"wires":[["60b8b9c0.cbfcb8"]]},{"id":"6bedfd5b.c3a6f4","type":"debug","z":"f5e33834.322d98","name":"","active":true,"tosidebar":true,"console":true,"tostatus":false,"complete":"payload","targetType":"msg","x":960,"y":260,"wires":[]},{"id":"4c3d0ace.8bbee4","type":"change","z":"f5e33834.322d98","name":"set param","rules":[{"t":"set","p":"folderid","pt":"msg","to":"16XagCyMW9wkCczhNo9H0FtWyPhN6tdhF","tot":"str"},{"t":"set","p":"mimeType","pt":"msg","to":"image/png","tot":"str"},{"t":"set","p":"payload","pt":"msg","to":"{\t \"resource\": {\t \"name\": filename,\t \"parents\": [\t folderid\t ]\t },\t \"media\": {\t \"mimeType\": mimeType,\t \"body\": payload\t },\t \"fields\": \"id\"\t}","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":640,"y":260,"wires":[["e9d133a3.0bfaf"]]},{"id":"cc93a9d6.ba07c8","type":"file in","z":"f5e33834.322d98","name":"*.png","filename":"","format":"","chunk":false,"sendError":false,"encoding":"none","x":490,"y":260,"wires":[["4c3d0ace.8bbee4"]]},{"id":"60b8b9c0.cbfcb8","type":"template","z":"f5e33834.322d98","name":"set filename","field":"filename","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"/home/enebular/enebular-runtime-agent/ports/awsiot/assets/{{payload}}.png","output":"str","x":330,"y":260,"wires":[["cc93a9d6.ba07c8"]]},{"id":"42b4ad6a.63db74","type":"google","z":"f5e33834.322d98","name":"","google":"","api":"drive:v3","operation":"drives.create","x":650,"y":100,"wires":[["e7039725.da7188"]]},{"id":"e9d133a3.0bfaf","type":"google","z":"f5e33834.322d98","name":"","google":"","api":"drive:v3","operation":"drives.create","x":790,"y":260,"wires":[["6bedfd5b.c3a6f4"]]}]
インポートするとエディタ上では、図のようになります。node-red-contrib-googleノード(以下、Googleノード)にエラーを示す赤い三角形がついています。これは、Google Driveにアクセスするためのクレデンシャル情報が設定されていないためです。
Googleノードの設定
では、Googleノードの設定を行います。
Googleノードをクリックして、編集画面を開きます。API欄にはdrive:v3
、Operation欄にはdrives.create
が設定されているはずです。設定されていないければ、以下の図を見て設定してください。次にConnectionの設定を行います。Connectionの鉛筆アイコンをクリックしてください。
JSON Keyの欄に、準備 Google DriveでダウンロードしたJSONファイルの内容を貼り付けます。ダウンロードしたJSONファイルをテキストエディタなどで開き、その内容をコピーして下図のように貼り付けてください。
JSON Key欄の下のScopes欄には、以下のように設定します。これは、編集画面のAPI Scopes
の欄をコピー&ペーストしただけです。本来は丁寧に必要なAPIを設定すべきですが、ここでは簡単にするために全てコピーしています。
これで、Googleノードの設定は完了です。Googleノードは2箇所にありますので、両方に設定してください。
Google DriveのフォルダIDの設定
ファイルをアップロードするGoogle Driveのフォルダをフローに設定します。
まずは、アップロード先のGoogle DriveフォルダのIDを取得します。ブラウザで、対象のフォルダを開いてください。下図に示したように、ブラウザのURLのfolders/
以下の部分がフォルダIDになりますので、メモをとっておいてください。
次に、メモしたフォルダIDをフローに設定します。
フローの図の中にset param
という名前のノードが2つあります。この2つのChangeノードが設定の対象になります(このフローでは2種類のファイルをアップロードするため、Changeノードを2つ使っています)。
set param
ノードをクリックして編集画面を開いてください。下図のようにmsg.folderid
を設定している箇所があります。ここに、先程メモしたフォルダIDを設定してください。2つのノードに同じように設定します。
これで、アップロード先のフォルダの設定が完了です。
フローの説明
出来上がったフローは保存してください。それでは、フローの中身を確認していきます。
フローは3段になっていますが、1段目の処理はグラフを作成する元データとなったcovid19.csv
をGoogle Driveにアップロードする処理です。
フローの起動(Injectノード)
このフローは、Injectノードで起動されます。フローのデプロイ&起動から30秒後に一回だけ起動する設定です。
covid19.csvの読み込み(file-inノード)
Injectノードに続く1段目のFile-inノードでは、covid19.csvファイルを読み込みます(covid19.csvファイルは、「設定ファイルをIoTデバイスにデプロイする方法」で作成したcsvファイルです)。Filenameに以下のようにcovid19.csvのパスを設定すると、ファイルの内容を読み込んで、msg.payload
の内容として出力してくれます。
/home/enebular/enebular-runtime-agent/ports/awsiot/assets/covid19.csv
Google Driveアップロードの設定(changeノード)
1段目のChangeノードでは、covid19.csvファイルをGoogle Driveにアップロードするための設定を行います。
msg.folderid
には前述の通りGoogle DriveのフォルダIDを設定しますmsg.filename
にはGoogle Driveにファイルを書き込む際のファイル名を設定しますmsg.mimeType
にはMIME形式でファイルのタイプを設定します。ここでは、text/plain
と設定しますmsg.payload
には以下の通りJSONata形式で設定します
{
"resource": {
"name": filename,
"parents": [
folderid
]
},
"media": {
"mimeType": mimeType,
"body": payload
},
"fields": "id"
}
設定ファイル(pref.csv)の読み込み(file-inノード)
2段目と3段目のフローでは、作成されたグラフ画像を読み込んで、Google Driveにアップロードします。
2段目のFile-inノードでは、pref.csv
ファイルを読み込みます。pref.csv
ファイルには、感染者数データを取得する都道府県名が記載されています。この都道府県名は、そのままグラフ画像のファイル名になります。
CSVの分割(csv, splitノード)
続くCSVノードは、受け取ったファイルの内容(msg.payload)をCSVとして解釈して、これをJavaScriptのオブジェクトに変換します(下図のようなオブジェクトになります)。このCSVノードは、デフォルト設定のまま使用しています。特別な設定は行わず、ノードを配置して前後のノードと接続しています。
{ col1: "東京都", col2: "大阪府", ... }
最後のSplitノードは、受け取ったJavaScriptのオブジェクトをバラバラのStringオブジェクトに分割してくれます。これで、設定ファイルの中に列挙された都道府県名を1つずつ扱うことができるようになりました(下図)。このSplitノードもCSVノードと同様に、デフォルト設定のまま使用しています。
東京都
大阪府
グラフファイルの読み込み(template, file-inノード)
3段目のTemplateノードでは、msg.payload
にファイル名を設定します。設定内容は以下の通りです。payload
には、Splitノードで分割した都道府県名(例:東京都)が格納されています。
/home/enebular/enebular-runtime-agent/ports/awsiot/assets/{{payload}}.png
続くFile-inノードでは、グラフ画像のファイル(例:東京都.png)を読み込みます。Output
はa single Buffer object
として出力します。Filenameは設定されていませんが、Templateノードでmsg.filename
に設定したファイルを読み込みます。
Google Driveアップロードの設定(changeノード)
3段目のChangeノードでは、グラフ画像のファイルをGoogle Driveにアップロードするための設定を行います。設定内容は1段目のChangeノードと全く同じです。
Node-REDフローのデプロイ
作成したNode-REDフローをデプロイします。
enebular-agentへのフローのデプロイの方法は、マニュアルのAWS IoTへのデプロイに詳しく記述されていますので、ここでは概要を説明します。
- enebularのダッシュボードから、フロー
free-fileasset-demo-flow
を選択します - フローのOverview画面には、”Deploy”ボタンがありますので押してください
- Connectionを選択します。Connectionの一覧から、上述の環境作成でenebular-agentをインストールした際に使用したConnectionを選びます
- Targetデバイスを選択します。デバイスの一覧から、上述の環境作成で指定したデバイス名を選びます
以上の手順で、フローがデプロイされて実行されます。
正しく動作していれば、Google Drive上のフォルダにconvid19.csvファイルとグラフ画像のファイルがアップロードされているはずです。
おわりに
ここまで2つの記事(1回目, 2回目) で、ファイルアセットの使い方について説明しました。
ファイルアセットは、アイディア次第でさまざまな面白い使い方ができます。この記事で、その一端でも感じていただけたなら幸いです。使用方法が分かりづらい場合は、遠慮なくenebularのサポートに連絡してみてください。